Preface:

The purpose of this article is to give you a quick introduction to The Angular8 and Baidu Maps API by implementing a step-by-step travel list project. We shall reap:

    1. Angular8 Basic usage, architecture
    1. Use Baidu map API to achieve their own map application
    1. Solve the cross-domain problem when calling baidu map API
    1. LocalStorage for basic encapsulation, data persistence
    1. Material UI

Project introduction

The background of the tourism List project is mainly for the author to better master Angular8, because the previous projects mainly used vue and React. To be a qualified coder, one must be knowledgeable and dedicated. It is also an idea that the author wanted to do in his early college years, that there could be such a program to record his journey. See and feel. The home page of the project shows the tourist sites and routes that have been to. The map route is realized by calling the BAIDU Map API. Of course, there are many such apis, and you can use them according to your own preferences. Secondly, we can add future travel planning and budget on the home page, which is convenient for later use. My mainland page mainly shows the routes you have been to and will go to, you can carry out related operations.

Project Address:

Develop travel list project based on Angular8 and Baidu Map API

Project structure of the Tourism List

Where components are stored, config is the common configuration area, home/newMap is the page area, mock is the simulated data area, service is the application required service area, such as HTTP service, storage service, custom.modules file is the third-party component placement area.

Results the preview

1. Start

  1. Assume you already have Node installed. If not, go to the Node website to install it. Erection of scaffolding:
npm install -g @angular/cli
Copy the code
  1. Create the workspace and initial application
ng new my-app
Copy the code
  1. Installation material UI
npm install @angular/material @angular/cdk @angular/animations
Copy the code
  1. According to the above schema, create the corresponding directory file
  2. Start the service
cd my-app
ng serve --open
Copy the code

The CLI automatically opens port 4200 of the browser and displays the default page.

2. Introduce Baidu Map API

The official API addresses for different map functions will be provided. Here is the address used for this project:

<script type="text/javascript" src="Http://api.map.baidu.com/api?v=2.0&ak= ak"></script>
<script type="text/javascript" src="http://api.map.baidu.com/library/CurveLine/1.5/src/CurveLine.min.js"></script>
Copy the code

If you do not have AK, please go to baidu map website to apply, the steps are also very simple.

Now that the basic project preparations are in place, let’s talk about Angular.

Basic Angular syntax and architecture

Basic grammar

Like vue, the basic syntax for ng is as follows:

  1. Template syntax
  2. Data instructions
  3. Attributes bind
  4. event

Here are some examples:

<h1>{{title}}</h1>
<h2 [title]="mytitle">My favorite hero is: {{ mytitle }}</h2>
<p>Heroes:</p>
<ul>
    <li *ngFor="let item of list">
      {{ hero }}
    </li>
</ul>
<button (click)="onclickBtn"> single < / button >Copy the code

*ngFor is a loop directive, *ngIf is a condition, and event binding is (click). Let’s look at the component’s TS file.

import { Component } from '@angular/core';
 
 
@Component({
  selector: 'app-root',
  templateUrl: './index.html',
  styleUrls: ['./index.scss']})export class AppComponent {
  mytitle = 'Xujiang';
  list = [
    'xujaing'.'zhangjiang'.'xakeng'
  ];
  onclickBtn() {
      console.log('hello')}}Copy the code

2. Basic architecture

Adopt the official Angular architecture diagram:

  1. The module

    Angular defines an NgModule. An NgModule declares a compilation context for a set of components that focus on an application domain, a workflow, or a closely related set of capabilities. Each Angular application has a root module, usually named AppModule. The root module provides the boot mechanism used to start the application. An application usually contains many functional modules.

  2. component

    Every Angular application has at least one component, the root component, that connects the component tree to the DOM in the page. Each component defines a class that contains the application’s data and logic and is associated with an HTML template that defines a view for display in the target environment, such as:

import { Component, OnInit } from '@angular/core';
import { LocationService } from '.. /.. /service/list';

@Component({
  selector: 'app-bar',
  templateUrl: './index.html',
  styleUrls: ['./index.scss']})export class AppBar implements OnInit {
    items;
    constructor(private locationService: LocationService) {
      this.items = this.locationService.getItems();
    }

    ngOnInit() {}}Copy the code
  1. Services and dependency injection

    You can create service classes for data or logic that is independent of a particular view and that you want to share across components. The definition of a service class usually follows the “@Injectable()” decorator. This decorator provides metadata that allows your service to be injected into the client component as a dependency. Such as:

```
import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
  })
export class Storage {}
```
Copy the code
  1. routing

    The Angular Router module provides a service that lets you define paths to navigate between the different states and view hierarchies of your application. As follows:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './home';
import { NewMapComponent } from './newMap'; Const routes: routes = [{path:' ', component: HomeComponent },
  { path: 'newMap', component: NewMapComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
Copy the code

4. Baidu map API and cross-domain problem solving

After entering the official website of Baidu Map, we go to the console to create an application. At this time, the corresponding application AK will be generated, as follows:

So install jquery:

npm install jquery
Copy the code

Solutions are as follows:

1. Encapsulate HTTP services:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { AK, BASE_URL } from '.. /config';
import * as $ from "jquery";

@Injectable({
    providedIn: 'root'
  })
export class Http {
    constructor(
        private http: HttpClient
    ) {

    }

    params(data = {}) {
        letobj = {... data, ak: AK, output:'json' };
        let paramsStr = '? ';
        for(let v in obj) {
            paramsStr += `${v}=${obj[v]}&`
        };
        return paramsStr.substr(0, paramsStr.length -1);
    }

    get(url, params) {
        return this.http.get(`${BASE_URL}${url}${this.params(params)}`)
    }

    getCors(url, params) {
        return new Promise((resolve, reject) => {
            $.getScript(`${BASE_URL}${url}${this.params(params)}`, (res, status) => {
                if(status === 'success') {
                    resolve(status)
                } else{ reject(status) } }); }}})Copy the code

Define jSONP callbacks and receive data variables:

let locationData = null;
window['cb'] = function(data) {
  locationData = data && data.results;
}
Copy the code

Use:

async searchLocation(v) {
  return await this.http.getCors('/place/v2/search',
  { region:v, query: v, callback: 'cb' });
}
Copy the code

Now that the main breakthrough points for the application have been addressed, let’s move on to developing the core pages and components of the project.

  1. Importing the materialUI component on demand:
// custom.module.ts
import { NgModule } from '@angular/core';
import { MatButtonModule, MatTooltipModule, MatBadgeModule } from '@angular/material';

@NgModule({
  imports: [MatButtonModule, MatTooltipModule, MatBadgeModule],
  exports: [MatButtonModule, MatTooltipModule, MatBadgeModule],
})
export class CustomMaterialModule {}Copy the code

Custom.module. ts is a file in the root directory, which I use as the location for storing third-party components. After defining it, I introduce it in app.module.ts:

// Material component library
import { CustomMaterialModule } from './custom.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    ReactiveFormsModule,
    AppRoutingModule,
    HttpClientModule,
    CustomMaterialModule,
  ],
  providers: [].bootstrap: [AppComponent]
})
Copy the code

BrowserAnimationsModule is an Angular module that provides some dynamic support for components. Next, let’s look at the entry page:

// app.component.html
<div class="app-wrap">
  <app-bar></app-bar>
  <main class="main">
    <router-outlet></router-outlet>
  </main>
  <app-footer></app-footer>
</div>
Copy the code

App-bar and app-footer define header and footer components for us, as follows:

// app-bar.html
<nav class="nav-bar">
    <div class="logo">Tourism map +</div>
    <a [routerLink] ="['/']">Home page</a>
    <a [routerLink] ="['/newMap']"><span [matBadge] ="items.length" matBadgeOverlap="false" matBadgeColor="warn">My mainland</span></a>
</nav>// app-bar.ts import { Component, OnInit } from '@angular/core'; import { LocationService } from '.. /.. /service/list'; @Component({ selector: 'app-bar', templateUrl: './index.html', styleUrls: ['./index.scss'] }) export class AppBar implements OnInit { items; constructor(private locationService: LocationService) { this.items = this.locationService.getItems(); } ngOnInit() { } } // footer.html<footer class="footer">@developer: {{name}}</footer>// footer.ts import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-footer', templateUrl: './index.html', styleUrls: ['./index.scss']}) export class AppFooter implements OnInit {name = 'implements OnInit '; constructor() { } ngOnInit() { } }Copy the code

SCSS will not be introduced here, because it is relatively simple, if you need you can go to my Github now complete project based on angular8 and Baidu Map API development travel list project to learn.

Second, the header component uses the LocationService. Let’s take a look at this service:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Storage } from './storage';

@Injectable({
  providedIn: 'root'
})
export class LocationService {
    items = [
      {
        name: 'Beijing'.desc: 'Beijing is great, the scenery is really great! '.price: '2000'.date: '2018-12-29'.hasDone: true.location: {
          lat: 39.910924.lng: 116.413387}}, {name: 'in suzhou'.desc: 'Suzhou is good, go still want to go, good! '.price: '2000'.hasDone: true.date: '2018-12-29'.location: { 
          lat: 31.303565.lng: 120.592412}}, {name: 'Shanghai'.desc: 'Shanghai is good, go still want to go, good! '.price: '2000'.hasDone: true.date: '2018-12-29'.location: { 
          lat: 31.235929.lng: 121.48054}}, {name: 'wuhan'.desc: 'Wuhan good, go still want to go, good! '.price: '2000'.hasDone: true.date: '2018-12-29'.location: { 
          lat: 30.598467.lng: 114.311586}}];constructor(
        private http: HttpClient,
        private store: Storage
    ) {
      if(store.get('list')) {
        this.items = store.get('list');
      }
    }
  
    addToList(location) {
      this.items.push(location);
      this.store.set('list'.this.items);
    }
  
    getItems() {
      return this.items;
    }
  
    clearList() {
      this.items = [];
      return this.items; }}Copy the code

We used @Injectable({providedIn: ‘root’}) to inject the service into the root component so that it could be shared. Secondly, we use our own encapsulated Storage service to carry out persistent data Storage. Storage service is as follows:

import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
  })
export class Storage {
    get(k) {
        return JSON.parse(localStorage.getItem(k))
    }

    set(k, v) {
        localStorage.setItem(k, JSON.stringify(v))
    }

    remove(k) {
        localStorage.removeItem(k)
    }
}
Copy the code

The implementation is relatively simple, so I won’t explain it here. Next, let’s look at the implementation of the core functions of the home page:

  1. Baidu Map initialization roadmap:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Input } from '@angular/core';
import { Http } from '.. /service/http';
import { FormBuilder } from '@angular/forms';
import { LocationService } from '.. /service/list';

@Component({
  selector: 'app-home'.templateUrl: './index.html'.styleUrls: ['./index.scss']})export class HomeComponent implements OnInit {
    hasDoneList;
    constructor(
      private locationService: LocationService,
      private http: Http,
    ) {
      this.hasDoneList = this.locationService.getItems();
    }

    ngOnInit() {
      let map = new BMap.Map("js_hover_map");
      // Create a map instance
      map.centerAndZoom(new BMap.Point(118.454.32.955), 6);
      map.enableScrollWheelZoom();
      let hasDoneLocations = [];
      this.locationService.getItems().forEach(item= > {
        item.hasDone && hasDoneLocations.push(new BMap.Point(item.location.lng,item.location.lat))
      })

      let curve = new BMapLib.CurveLine(hasDoneLocations, {strokeColor:"red".strokeWeight:4.strokeOpacity:0.5}); // Create an arc object
      map.addOverlay(curve); // Add to the map
      curve.enableEditing(); // Enable the edit function}}Copy the code

In the ngOninit lifecycle, we initialize the map data and filter the hasDone data to true according to the list server we defined earlier. Next we implement the ability to add a travel list. 2. Add a travel list

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Input } from '@angular/core';
import { Http } from '.. /service/http';
import { FormBuilder } from '@angular/forms';
import { LocationService } from '.. /service/list';

// Get a callback for cross-domain data
let locationData = null;
window['cb'] = function(data) {
  locationData = data && data.results;
}

@Component({
  selector: 'app-home'.templateUrl: './index.html'.styleUrls: ['./index.scss']})export class HomeComponent implements OnInit {
    hasDoneList;
    checkoutForm;
    constructor(
      private formBuilder: FormBuilder,
      private locationService: LocationService,
      private http: Http,
    ) {
      this.hasDoneList = this.locationService.getItems();
      this.checkoutForm = this.formBuilder.group({
        name: ' '.price: ' '.date: ' '
      });
    }

    ngOnInit() {
    ...
    }

    async searchLocation(v) {
      return await this.http.getCors('/place/v2/search',
      { region:v, query: v, callback: 'cb' });
    }

    onSubmit(customerData) {
      if(customerData.name) {
        this.searchLocation(customerData.name).then(data= > {
          this.locationService.addToList({... customerData,location: locationData[0].location, hasDone: false})}); }else {
        alert('Please fill in the destination! ');
        return
      }

      this.checkoutForm.reset();
    }

    onReset() {
      this.checkoutForm.reset(); }}// html
<div class="home-wrap"> <div class=" done"> <div class="title"> </div> <div class="visit-list"> <button *ngFor="let item of hasDoneList" class="has-btn" mat-raised-button [matTooltip]="item.desc" aria-label=" button display tooltip "> {{item.name}} </button> </div> <div class="has-done"> <div class="title"> <div class="future-list"> <form [formGroup]="checkoutForm"> <div class="form-control"> <label> </div> <div class="form-control"> <div class="form-control"> </div> <div class="form-control"> <label> Date: </label> <input type="date" formControlName="date"> </div> <div class="form-control"> <button mat-raised-button Color ="primary" class="submit-btn" type="submit" (click)="onSubmit(checkoutForm.value)"> </button> <button < div> </form> </div> </div> </div> </div> </section> <section class="map-wrap" id="js_hover_map"></section> </div>Copy the code

We use the angular FormBuilder to process the form data. Note that when we submit the form, we need to call the baidu map API to generate the latitude and longitude data and then add it to the list. The purpose of doing this is to provide the latitude and longitude data to the baidu map API in order to draw the road map. Also, since access is cross-domain, we need to define jSONP callbacks to get the data, as follows:

let locationData = null;
window['cb'] = function(data) {
  locationData = data && data.results;
}
Copy the code

The locationService’s addToList method adds the data to the list and stores it in the storage. For the full code, please check it out on my Github.

The next step is to look at my mainland page, which is not so difficult as to display different styles based on whether hasDone is true or false.

The code is as follows:

// html
<div class="detail""> <div class="position-list">
        <div class="position-item" *ngFor="let item of list">
            <span class="is-new" *ngIf=! "" item.hasDone"Word-wrap: break-word! Important; "> <span class="title">{{item.name}}</span>
            <span class="date">{{item.date}}</span>
            <span class="desc">{{item.desc}}</span>
            <span class="price"</span> </div> </div> </div> // ts import {Component, OnInit} from'@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Input } from '@angular/core';
import { LocationService } from '.. /service/list';

@Component({
  selector: 'app-new-map',
  templateUrl: './index.html',
  styleUrls: ['./index.scss']})exportclass NewMapComponent implements OnInit { @Input() product; // Specify that the product value is passed from the parent component; constructor( private route: ActivatedRoute, private locationService: LocationService ) { this.list = locationService.getItems(); } editItem(item) { }ngOnInit() {
        this.route.paramMap.subscribe(params => {
            // this.product = products[+params.get('productId')]; }); }}Copy the code

conclusion

This project is based on angular8 practical entry project, involving some advanced skills and Baidu map, JSONP cross-domain knowledge, we have not understand can communicate with each other, I will regularly share some of the core technology commonly used in the enterprise.

Incomplete part: When adding the list, if you add an address that does not meet the specification or cannot be found on Baidu map, an error message will appear. This part will be optimized in the later stage.

Well, the article length is more, roughly the project is basically completed, if you want to see the actual project effect, please move based on angular8 and Baidu map API development travel list project.

Finally, more technical quality articles and technical data are welcome to pay attention to the “Interesting Talk Front Public Account” :

Welcome to join the front end technology group and discuss the charm of the front end: