Angular update directive_angularjs based on service status

Source: Internet
Author: User
Tags emit

Angular JS (angular.js) is a set of frames, templates, and data binding and rich UI components that are used to develop Web pages. It supports the entire development process, providing a framework for Web applications without the need for manual DOM operations.

Angularjs is designed to overcome the lack of HTML in building applications. HTML is a good declarative language for static text presentation, but it is weak to build a Web application. Here Angularjs, make up for the natural defects of HTML, used for component Web applications.

Tl;dr

This article explains three ways to update directive based on the status of the service. are $watch expressions, event passing, and controller computed properties.

Problem

I have a readerservice that contains some state information (such as connection status and battery power). Now I need to do a directive to show these states. Because it only needs to get the data from the Readerservice, no external values are needed, so I inject the service directly into it. But how to update it becomes a problem.

The service code is as follows.

Const STATUS = {
DETACH: ' DETACH ',
ATTACH: ' ATTACH ',
READY: ' READY '
}
class Readerservice {
Constructor () {this
. Status = Status
//The status is changed by some callbacks
This.status = status. DETACH
}
angular.module (' app '). Service (' Readerservice ', Readerservice)

The directive code is as follows:

Angular.module (' app '). Directive (' Readerindicator ', (readerservice) => {
Const STATUS = readerservice.status
Const Status_display = {
[STATUS]. DETACH]: ' Disconnected ',
[STATUS. ATTACH]: ' Connecting ... ',
[STATUS]. READY]: ' Connected ',
} return
{
restrict: ' E ',
scope: {},
Template: '
<div class= ' Status ' >
{{statusdisplay}}
</div>
',
link (scope) {
//Set and change Scope.statusdisplay here
}}}
)

I have tried the following methods, described below.

Method One: $watch

The first way to think of it is to use $watch in directive to monitor readerservice.status. Because it is not a property of the directive scope, we need to wrap it with a function. Angular will calculate and compare the old and new values at dirty-checking, only if the state really changes to trigger the callback.

In directive
link (scope) {
scope. $watch (() => readerservice.status, (status) => {
Scope.statusdisplay = Status_display[status]}
)
}

This approach is simple and efficient enough, as long as the code involved in Readerservice.status changes triggers dirty-checking, directive is automatically updated. Service does not need to modify any code.

However, if you have multiple directive attributes that are affected by the service status, the $watch code is more obscure. In particular, $watch modified values can affect other values. Like what:

In directive
link (scope) {
scope. $watch (() => readerservice.status, (status) => {
Scope.statusdisplay = Status_display[status]
scope.showbattery = status!== status. DETACH
})
scope. $watch (' Showbattery ', () => {
//Some other things depend on Showbattery
})
}

This is a time when declarative programming styles are easier to read, such as the computed property in Ember or Vue. This will be discussed later.

Method Two: $broadcast/$emit + $on

The idea is that the service sends an event each time the state changes, and then directive the listener event to change the state. Because the status has been updated when directive renders. So we need to compute an initial value in link.

I started out with $broadcast. The code is as follows:

In service
SetStatus (value) {
This.status = value
//Need to inject $rootScope this
. $rootScope. $ Broadcast (' reader.statuschanged ', This.status)
}
//in Directive
link (scope) {
Scope.statusdisplay = Status_display[nfcreaderservice.status]
scope. $on (' reader.statuschanged ', (event, STATUS) => {
Scope.statusdisplay = Status_display[status]}
)
}

But immediately after $broadcast the UI update has to wait more than 1 seconds (but $on callback is fast). Google knows the reason is that $broadcast is to the lower level of all the scope of the broadcast, the broadcast is completed after dirty-checking. A better approach is to use the $emit, which only passes events up, but it takes $rootScope regardless of whether the event is sent or monitored.

The modified code is as follows:

In service
SetStatus (value) {
This.status = value
/$emit instead of $broadcast this
. $rootScope. $emit (' reader.statuschanged ', This.status)
}
//in Directive
link (scope) {
Scope.statusdisplay = Status_display[nfcreaderservice.status]
//Use $rootScope instead of scope
$rootScope. $on (' Reader.statuschanged ', (event, status) => {
scope.statusdisplay = Status_display[status]
})
}

If you have to use $broadcast for some reason, you can use $digest or $apply to force the dirty-checking at the end of $on callback, which can also be used to quickly update the UI.

Method Three: Controller + property

I personally think the first two methods can solve the problem, but the code maintenance is not very good. $watch are very difficult to understand when attributes are interrelated, $emit/$on need to write some of the logic two times (initializing directive and callback execution). Method One I mentioned that sometimes declarative attributes are easier to read than $watch. The method is to use controller. Directive can set its own controller as a data source (or view model), we can take those attributes that need to be computed as controller properties. They are calculated automatically when they are dirty-checking.

In directive
class Readercontroller {
constructor ($scope, Readerservice) {
This.readerservice = Readerservice
} Get
Statusdisplay () {return
status_display[this.readerservice.status]
}
} return
{
//...
Controller:readercontroller,
controlleras: ' vm ',
Template: '
<div class= ' status ' >
{ Vm.statusdisplay}}
</div>
}

As a result, most of the logic can be moved to controller. We can even write the link method without the DOM operation. There is no need to add additional $watch and $on. Just because of the dirty-checking feature, the properties bound to template tend to be counted several times. So the attribute must be very simple. In most cases this will not be a problem.

The above content is small series to introduce the angular according to the status of the service Update directive, I hope to help you!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.