Method for interacting control using Angular2 OBServables

In Angular1.x, we use Promise to handle various asynchronous. However, in Angular2, it is useful for Reactive Extensions (RX) Observable. There are many articles on the Internet, there are many articles on the Internet, and this 7-minute video on Egghead.IO is recommended (Author Ben Lesh). In this video, mainly, use Observable created asynchronous tasks, can be processed, and it is labeled. In this article, we mainly have problems encountered when interacting with the server, to see the features that OBSERVABLE give us.

Example Scene

First, let’s define the scenes of the problem. Suppose we want to implement a search function, there is a simple input box that when the user enters the text, real-time use of the input text to query and display the results of the query.

In this simple scene, it is generally necessary to consider 3 problems:

cannot enter each time The search is triggered when you character.

If the user enters each character, it triggers a search. Wash the server resources, two clients frequently trigger searches, and updating search results, will also affect client responses. Generally, this problem is avoided by adding some delays.

If the text is not changed, it should not be re-searched.


Suppose the user enters ‘foo’, pauses for a while, triggered a search, and knocked a character ‘o’, and found that it was wrong, and deleted this. character. If the user stops for a while, it will trigger a search. This time the text ‘foo’ is the same as the previous search, so you should not search again.


To consider the problem of asynchronous returning of the server.


When we use asynchronous ways to send multiple requests to the server side, we need to pay attention to the order in which the returned is not guaranteed. For example, we have searched 2 words ‘computer’, ‘car’, although ‘car’ words are later found, but there is a possibility that the server handles this search is faster, just return the result. This page will first display the search results of ‘car’, and then the result of the ‘Computer’ is displayed when the search results of ‘Computer’ are received. However, at this time, it seems that it is clear that it is the ‘car’, but it shows additional results.

In this example, we use Wikipedia’s API interface to develop a simple instance to implement simple search features.
Implementing the search


Since it is just a demo, we only contain 2 files in our app: app.ts and wikipedia-service.ts, the final version For the source file, please refer to the Demo link provided in the original text.

We directly see how the original version of WikipediaService is implemented:

Import {INJECTABLE} from ‘@ Angular / Core’; import {urlsearchparams, Jsonp} from ‘@ angular / http’; @ Injectable () export class WikipediaService {constructor (private jsonp: Jsonp) {} search (term: string) {var search = new URLSearchParams () search.set ( ‘action’, ‘ OpenSearch ‘); SearcH.SET (‘Search’, Term); Search.Set (‘Format’, ‘Json’); Return this.jsonp.get (‘http://en.wikipedia.org/w/api.php?callback= Jsonp_callback ‘, {search}). TOPROMISE () => Response.json () [1]);}}

Using the JSONP module to request the API result, its result should be an object of the type OBSERVABLE
, we convert the return result from Observable

to the Promise

object, then use its THEN method to put the result Turn into JSON. In this way, the return type of this Search method is promise

>.

Note the above, we use the response.json () [1], from the original result, get the list of query results we need, the list is String.

This looks very simple, in Angular1.x, it is basically using $ HTTP or $ Resource to return a promise type.
 The following is part of app.ts (because this is just a demo, so directly define Module and Component directly in app.ts, and call service, in real App, you should create the corresponding components to implement :   
// Check the PLNKR for the full list of importsimport {…} from ‘…’; @ Component ({Selector: ‘My-app ‘, Template: “
Wikipedia Search

<Array `}) Export Class AppComponent {Items: Array

; Constructor (Private Wikipediaaservice): Wikipediaaservice: Wikipediaasemp ) {} search (term) {this.wikipediaasenvice.search (term) .Then (items => this.items = items);}}

from the above code It can also be seen that AppComponent has a search () method, which calls wikipediaaservice.search () method, because this method returns a promise

> type result, so use the1 (), assign the result list to Model object Items . The template content inside the above Template is used to display the result of the query with a list.
Although this implementation satisfies the basic query function, it is not possible to solve the three problems mentioned above. Below to modify this implementation to solve the above problems.
  
Controls the user input delay

We first solve the first problem: When the user is entered, don't trigger a search every time you enter a character. Instead, set a time delay, and trigger a search when the user stops input for more than 400 milliseconds. If the user has not stopped, the input time interval is less than 400 ms. This is what 'observables' can do.
    To this end, we need an OBSERVABLE
  • object to save the user's input, and then you can use the method provided by this object to implement the delay trigger. We can use Angular2's instructions (Directive)OrmControl. To use this instruction, you need to introduce the ReactiveFormSModule module.
Import {ngmodule} from '@ Angular / Core'; import {browsermodule} from '@ Angular / Platform-Browser'; import {jsonpmodule} from '@ Angular / http '; import {ReactiveFormsModule} from' @ angular / forms'; @ NgModule ({imports: [BrowserModule, JsonpModule, ReactiveFormsModule] declarations: [AppComponent], bootstrap: [AppComponent]}) export class AppModule {}
After introducing, we can use formControl in the template to create a form input and set a variable name Term.

<Array

This, the variable TERM binding this INPUT component is an instance of FormControl, It has a property ValueChange, which is an object of OBSERVABLE . We can use the DebounceTime method of OBSERVABLE
to set the trigger delay.

Export Class AppComponent {Items: Array

; Term = New FormControl (); constructor (private wikipediaService: WikipediaService) {this.term.valueChanges.debounceTime (400) .subscribe (term => this.wikipediaService.search (term) .then (items => this.items = items)); }}

We see this.term.valueChanges is an Observable object, with Debouncetime (400) We set its event trigger delay is 400 ms. This method still returns an OBSERVABLE
 object. Then we add a subscription event to this object:   
Term => this.wikipediaasenvice.search (term) .Then (items => this.Items = Items

This is a method written by the LAMBDA expression. The parameter TERM is the OBSERVABLE

object through 400ms delay settings, generated by a user input string. The method is to search with this parameter, which is consistent with the previous version.
In this modified version, we remove the previous search () method, add directly in the constructor constructor (…), which is equivalent to the input of the user in the input box, is a message Source, will pass the debounce timing (400), then generate a message, this message is sent to the subscribed event handler to process, that is, the search. Therefore, we do not need a search () method to control when it is triggered, but by the mechanism of the type subscription.
  Prevent trigger twice  
Now let’s solve the second problem, it is the same situation as the user enters the search cruise after 400 ms. With the OBSERVABLE above, this is very simple. Observable has a DistinctUntilChange method. He will determine whether the new data from the message source is consistent with the last data, only inconsistency will only trigger the subscription method.

THISTINCTIME (400) .distinctuntilchanged (). Subscribe (Term => this.wikipediaasenvice.search (item) .Then (items => this

 Treatment Return Order    
The above describes the server side is asynchronous to return data. The problem of inconsistencies in the return order. For this problem, our solution is directly, that is, the result returned for the previous request, directly ignored, only processing the results of the last initiated request on the page. Say that the previous request, if you look at the video above, or know the difference between Promise and Observable, you should think that we can use the OBSERVABLE DISPOSE () method to resolve. In fact, we use this ‘Disposable’ characteristic to solve, rather than directly call the Dispose () method. (I really don’t know how to translate ‘Disposable’, it means that I can stop the message processing on the OBSERVABLE object, the literal meaning can be discarded, one-time.)
Above we talk In the Search () method of the service, we turn the result of JSONP from Observable

.Change to Promise . In order to use Observable characteristics to discard the result of the previous return, we let this method returns the result of the OBServable type. Below is the Search () method in the modified Wikipediaaservice.

Search (Term: string) {var search = new urlsearchparams () search.set (‘Action’, ‘OpenSearch’); Search.Set (‘ Search ‘, Term); Search.Set (‘ Format ‘,’ JSON ‘); return this.jsonp.get (‘ http://en.wikipedia.org/w/api.php?callback=jsonp_callback “, {SEARCH }). Map ((response) => response.json () [1]);}
Note this method is last used. map ((response) => Response .json () [1]) means that for the original Response type result, convert to a list of actual search results.
   Map () and methods such as flampmap (), which are commonly used in function-based programming, meaning every data in the original data set, through A certain process returns a new result, which is to convert a data set into another dataset. 
Now, our Wikipediaaserice’s return result is not promise, so we need to modify app.ts, we cannot use the the () method to handle results, but use subscribe () Add a message subscription method.

This.Term.Valuechanges.debouncetime (400) .distinctuntilchanged (). Subscribe (Term => this.wikipediaasenvice.search (term) .Subscribe (items => this.Items = items);

Among them, the first Subscribe ():

this.term.ValueChanges … subscribe (term =>. …)

This is a query string generated by the input box, registering a subscription method to process the user’s input.
   
this.wikipediaasenvice.search (term) .subscribe (items => this.Items = items );

is the result of the data query from the server side, register a subscription method to assign this data to Model.

We can also use the following way to avoid using multiple Subscribe:

this.term.valuechanges.debouncetime (400) .distinctUntilchanged ) .flatmap (term => this.wikipediaasenvice.search (term)). Subscribe (items => this.Items = items);

We have called the flatmap (…) method on the Observable
 of the string entered by the user, which is equivalent to calling Wikipediaaservice for each valid query condition input to the user. .Search () method. Then register a subscription method to the data returned to this query.   Have a big space, I hope you understand the Observable's FlatMap and Subscribe usage. For those who have been programmed, this is really hard, but in Angular2, we will A large number of methods of various functional programming are used. So you still need you to spend time. 
Too much effort, the above seems to have no relationship with ‘ignored message’, then there is no relationship, then the above modification does not solve that problem. No! Has no. Because we use FlatMap, each valid query string entered by the user will call the subscribed process, and then update Model. So our question is still not resolved.
But after this step, the solution is very easy, we only need to use the SwitchMap agent flatmap. It’s that simple! This is because SwitchMap will directly cancel the subscription method of the previous message directly in the process of processing each new message.


Finally, optimize the code:

@component ({Selector: ‘my-app’, template: `

Wikipedia Search
{{Item}}
 `}) Export Class AppComponent {Items: Observable >; Term = New FormControl (); Constructor(Private wikipediaService: WikipediaService) {this.items = this.term.valueChanges.debounceTime (400) .distinctUntilChanged () switchMap (term => this.wikipediaService.search (term));.}}  

We directly assigned the results of switchmap () to Model object, which is an OBSERVABLE

> type of data. In this way, it is also necessary to modify the use of items in the template. You can use asyncPipe:
   
{{item}}

In this way, the template is automatically parsing the result of this OBSERVABLE, rendering the page.

Demo Address: Smart Wikipedia Search Using Angular 2
 The above is all the content of this article, I hope to help everyone, I hope everyone will support Tumi Cloud.                      
© Copyright Notice
THE END
Just support it if you like
like0
share
comment Grab the couch

Please log in to comment