We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.
So Angular 2 basically uses the Flux Architecture? :-)
Angular will not force an architecture on you, but the new change detection and the Forms API, which I will write about in detail soon, make Flux a good option.
Btw, you can already build Angular 1.x apps using Flux http://victorsavkin.com/pos....
Angular 2 doesn't come with any architecture strings attached? Can you clearify?
Interesting stuff, thanks! One question: how exactly do observables avoid cascading updates? My understanding is that in Angular 1.x, cascading updates are dealt with by repeating the $digest() loop until no further changes are detected. Won't that still be true? Thanks to the new immutable and observable features you outline, each loop will have less to process, but it still needs to repeat until a stable state is reached, right?
Thanks.
In Angular2 we walk the change detection graph only once (TTL = 1). This is possible because the graph does not have any cycles.
What I meant by cascading updates is the following:
Say we have three observable objects: ObjectA, ObjectB, ObjectC. Consider the following situation.
- ObjectA fires an event
- The view rendering ObjectA catches the event and rerenders
- ObjectB catches the event and fires its own event
- The view rendering ObjectB catches the event and rerenders
- ObjectC catches the event and fires its own event
- ObjectA catches the event fired by ObjectC
...
Note how the framework calls (view.render) are interleaved with the events. It is hard to tell what gets rerendered when. This is a real problem of many front-end frameworks.
In Angular2 it works as follows.
- ObjectA fires an event
- ObjectB catches the event and fires its own event
- ObjectC catches the event and fires its own event
- ObjectA catches the event fired by ObjectC
While it is happening the framework is marking the parts of the change detection graph that are updated. This marking has no observable side effects. At the end of the VM turn the framework will check only the marked paths and update the bindings.
Note that there is a clear separation of when the model is updated and when the framework does its magic. The bindings would be updated in the same order if ObjectA, ObjectB, and ObjectC were not observable. This is very important.
Hi Viktor, I'm pretty late to the party, but this is really cool stuff.
From what I understand, Angular1 runs the digest every time a change occurres (an event is fired), which has performance side effects, while Angular2 runs in 2 different phases:
- 1st phase: listening to the events and marking the changed components
- 2nd phase: rendering the new state (which contains only the marked components, thus being way faster).
My question is, when is phase 2 kicking in, or how does Angular know when to start it?
The first phase is reacting to events and updating components and domain objects. Btw, nothing gets marked unless you use ON_PUSH components.
The second phase is rendering the new state. Angular knows when to run it because it is built on top of Zone.js. Zone.js provides hooks that are invoked on every browser event and every mircotask. Angular uses these hooks to rerender the view.
Great. Thanks a lot for the answer.
So to use immutable objects I have to inform angular2 about it by implementing onChange method in the component? And if I want to use observables I'd have to use objects of type Observable?
A working TodoApp would help better understand the change detection in A2.
>> So to use immutable objects I have to inform angular2 about it by implementing onChange method in the component?
You can use immutable and observable objects without telling Angular about it, but then you won't get any performance benefits out of it. To get the performance benefits you need to tell the framework that you depend only on immutable or observable objects.
>> And if I want to use observables I'd have to use objects of type Observable?
You won't have to use any special Observable class. Any push-based object can be used here (e.g., Object.observe or Rx observables). The framework does not make any assumptions about the type of your observables. Likewise, the framework does not make any assumptions about what is immutable.
>> A working TodoApp would help better understand the change detection in A2.
I am putting something together that will show advanced scenarios of using the change detection.
Waiting for that "something together" victor. It will help to understand better.
One more question, the above syntax is not native js. Is it AtScript syntax?
>> To get the performance benefits you need to tell the framework that you depend only on immutable or observable objects
And how exactly does one do that? Your post is very unclear on this particular point.
You do that by setting the change detection strategy to ON_PUSH, which means that only when bindings are pushed, the component's view should be checked.
@Component({
changeDetection:ON_PUSH
})
class DependsOnlyOnImmutableData {}
Hi Victor,
How can we inform angular that there are changes on the component (when using ON_PUSH)?
Can we be running outside angular's zone and still do this?
You can. Call `markForCheck` on a change detector ref, and then call LifeCycle.tick.
Perfect, thanks!
How does angular 2 know to wait for change of "todos" or "todo" variable? Do all of the expressions within the template create a watch that triggers re-rendering of the component if
1) reference changes (in case of ON_PUSH change detection) or
2) variable is an Observable and the observable fires
?
When not using OnPush detectors, then it just checks all bindings on every browser event similar to Angular 1.
When using OnPush detectors, then the framework will check an OnPush component when any of its input properties changes, when it fires an event, or when an observable fires an event.
Your observable example didn't have OnPush, so I'm not sure I understood it quite yet ;).
Hi Victor, I am a big fan of your works. I am designing an inventory prediction system based on angular2 and following the webcomponent standards. Thereby I have encountered certain problem on the way. 1) Whenever I inject a dependecy it by default gives me a new instance of the component. 2) Change Detection algorithm is still a bit not clear to me. It is always evolving, but certain fundamentals could have been achieved using observables. I have made a small diagrame if you can help me to achieve this particular feat:
The idea is very simple: The user clicks on a slice of the pie -> This calls the api and populates sales data using fetch (still hate angular2 http) -> changes the data in salesforce -> triggers the salesforcegraph to change.
If you are interested I can share the code with you somehow.the github is : https://github.com/debanjan...
Thanks for your enthusiasm for Angular! Unfortunately, we're really busy working on delivering Angular 2 beta right now, and it's not possible for me to respond to individual requests for help. The best way to get help would be to post on the public list (e.g., stackoverflow).This will also help other community members
In the observable-sample above, what would happen, if the first todo-item-component had some sub-components. Will they be checked too, when the first todo-item-component raised an event?
If you have the following component tree
A
|
B
|
C
And B raises an event, A and B will be checked. If, however, C gets updated during the check, then C will be checked too.
I see. In this case, C would also have to raise an event, when it it is updated during the check, right?
Victor Savkin would you have mix the use of Observables with Immutables? Or does using one make the other unneccessary?
I think using the two in the same app is totally reasonable.
Simple immutable objects are great for representing records, static collections, and in general facts. Rx Observables are useful for expressing variable things.
For example, a todo and a list of todos can be immutable. But the notion of the current list of todos is mutable. An observable of immutable lists of todos is a good way to model this.
Thanks! I would LOVE to see a post about how to properly mix the two with real code examples.
How can I manual run change detection or subscripe it for example in component.js
this.service.ajaxCall((result) => {
this.todos = result.todos; //change
this.findNewElementInDOM(); // dont't work
--> Don't runned the change detection here, but I only can here cach the async call and detect change
});
--> change detection only run after ajaxCall callback executed
Its nearly similar to React and Flux using immutable.js along with it
I'm wondering, when the digest-phase is triggered. You mentioned that it's triggered on every browser-event. But I've noticed, that the view is even updated, when I update the bindings in an async success-handler, angular2 isn't aware of. As I don't use observables this seems quite magic to me ...
I've found the answer to my question: zone.js creates hooks for events ...
Could you point to the code where this happens? I was also asking myself similar question.
Sure. Have a look here: https://github.com/btford/z...
Zone.js rewrites the properties of JavaScript-prototypes to get notified, when an event happens ...
So, how does it differ from React? It looks to be almost the same now... Well, except they've invented their own language now, Hooray :( Sure you can do it in plain JS, but then you end up with the same mess as in Angular 1. Moving stuff out of your api and into annotations, doesn't make your api better.
It seems angular 2 will loose a huge amount of convenience for the developer in trade for performance, while the angular folks been preaching angular 1 didn't have a performance problem because you never need to show more than 2000 bound items at once etc. And to be honest, angular 1 is performing just fine and I'd rather keep my speed of development than get performance I don't need. If people need it, let them use React. Now we seem to loose the choice and get 2 times React.
While I see this point just like you, I hope, that there will be some syntax sugar, that will bring back the convenience from 1.x to 2.x ...
Forgive me, but didn't Knockout.js effectively implement this four years ago?
If you are referring to the notion of Observables, then, yes, most frameworks support observable models. Most frameworks, however, require you to use a particular kind of observables and suffer from cascading updates.
Angular does not force you to use one kind of observables: you can use rxjs, object.observe, backbone models, probably even knockout models. It can take advantage of any of them because the described mechanism is more generic.
The most important thing is that you don't have to use observables at all and instead take advantage of immutable objects. The framework remains model agnostic.
Knockout does not require you to use observables if a model property does not mutate; it will quite happily bind plain properties - it just won't react to mutations. You can even place computed properties in front of multiple observables, and Knockout will only update the computed's subscribers when the computed's result actually changes.
Knockout provides a great deal of fine control over how mutation propagates; the utils it provides make it easy to write performant code naively. I think it's a real shame that so many developers dismiss it without even looking at it.
This is an important statement here: "The most important thing is that you don't have to use observables at all and instead take advantage of immutable objects."
One of the biggest draws to Angular 1.x was the idea of not requiring an implementation of wrapping objects with observability. We could use raw javascript objects. Anyone who has done this in Knockout or other similar observable tech (IObservable in .NET even) knows the cost of it is you always have to convert your objects (or wrap them) with this feature. Can you clarify your statement here on how immutable objects can be used, say, given a todo:
[
{ id: 1, description: 'go shopping'},
{id: 2, description: 'take kids to school'}
]
There are three problems with using immutable objects in Angular 1.x:
- Angular does not know that they are immutable and keeps checking them. So it is not efficient.
- Custom immutable collections do not work with NgRepeat out of the box .
- NgModel does not play nicely with immutable objects.
Angular2 solves all of them.
- The change detection gives you a mechanism to express that the component depends only on immutable objects and, therefore, should not be checked until one of the bindings gets updated, as follows:
// There will be a way to express it declaratively
class ImmutableTodoCmp {
todo:Todo;
constructor(private bingings:BindingPropagationConfig){}
onChange(_) => bingings.shouldBePropagated();
}
- The change detection is pluggable, so you can teach it to detect changes in any collection.
- The new Forms API is immutable object friendly.
In Angular2 using immutable objects feels natural. You can pass an immutable collection to a repeater.
<todo !foreach="var t in todos" [todo]="t">
Use an immutable object in your template
{{todo.description}}
Even though Angular2 "just works", you will have to change the way your app is architected if you make most of your models immutable. This is not Angular specific. This will be true in any framework. That is why there are such things as Flux and Cursors (https://github.com/omcljs/o....
It appears that json objects will have to be converted to an object of this type and cannot be used as is. Unless I misunderstand. Right?
We may gain Perf but we lose something big there.
Sorry, I was not clear. We can define Todo in TypeScript as follows:
interface Todo {
description:string;
checked:boolean;
}
So Todo just defines the shape of the object. It can be a regular JSON object with the two fields.
Will A2 apply DOM changes all at once (batch update) like ReactJS? I couldn't find something like "task queue" in the code base.
Yes. DOM updates will be applied at once.
Cool. Looking forward to your next blog post.
It seems it's safe to conclude that Angular apps are not written anymore in JavaScript, but in Angular language. Probably this will never make it popular.
It is written in TypeScript (https://twitter.com/ngconf/...
> bingings.shouldBePropagated();
Not so sure about propagating bingings!!!