How to force view update in middle of code execution? - javascript

Every once in a while I have a situation where my code changes some variable binded to the view, or even change some attribute of a Dom element, but the view renders only when all the code is executed, when I usually I don't need the effect anymore, like for example an animation for an Ajax data load.
Is there a way or a command that forces the DOM or Angular to revalidate its bindings or simple refreshes the view?

If I understand your problem correctly it looks like you need to run change detection manually.
ChangeDetectorRef.detectChanges() would trigger change detection for view and child components.
ChangeDetection Docs

Related

equivalent to ngAfterViewInit but general for all views

When views DOM is heavy, sometimes it gets some time to render it, especially on older mobile devices. I would like to put a spinner whenever the view is not rendered yet.
I can achieve that using ngAfterViewInit hook but doing it for every view provides a lot of duplicated code.
I was wondering if there is a global hook that is fired whenever rendering of current view is done.
As Jota mentioned in a comment, what you're asking for doesn't exist in angular. Something you could do, which may or may not be appropriate to your situation, is add a single spinner component to the root of your app (say, in app.component.ts) and create a service which can turn it on or off. This way, in each of your child components you could turn the spinner on in ngOnInit and turn it off in ngAfterViewInit.
Another option, if you're using the Angular Router, is to have this spinner component listen for router events: turning on at NavigationStart and turning off at NavigationEnd.

Does Angular 2 have re-rendering optimization?

I have been using React from couple of months and React doesn't simply re-rendering a component completely instead it finds the difference and makes those changes. Does Angular 2 does something like this?
And also whenever a change in state is detected does Angular 2 re-render all the components from the root node or does it only re-render those specific components and their sub-tree whose change is detected?
React doesn't simply re-rendering a component completely instead it finds the difference and makes those changes. Does Angular 2 does something like this?
Conceptually yes, it does not re-render entire components.
Angular builds a change detector object for each component/directive. Template bindings (which includes input property bindings) are tracked inside these change detector objects. When change detection runs, by default, each binding is dirty checked for changes. If a change is found, the changed value is propagated to the child component (if an input property changed) or to the DOM. That's it. The entire template/view is not re-rendered. Only the changed values are updated in the DOM. When Angular change detection finishes, the browser notices the DOM changes and updates what we see on the screen.
whenever a change in state is detected does Angular 2 re-render all the components from the root node or does it only re-render those specific components and their sub-tree whose change is detected?
Angular doesn't detect changes to some model/data objects. Rather, it only detects changes to template bindings.
By default, each time change detection runs, it starts from the root component and checks all components for changes, in depth-first order, using those change detector objects. As described above, only template bindings with changes are updated. So, I wouldn't say that Angular ever re-renders a component... it only modifies those parts of the DOM where a template binding changed.
You can configure a component to use the OnPush change detection strategy to limit when that component and its descendants are checked for changes. You can also completely detach() a component from the change detector tree, which means that component and its descendants will not be change detected until you reattach().
Angular is not using virtual DOM as React do. No need for that in context of Angular.
If you have <input> and need to set its value in runtime to something else you don't need to change all DOM around it. You just call setValue() on that element and that's it.
The same applies to any other DOM element. For example if you have this:
<div>{{someVar}}</div>
and Angular detects that someVar was changed it will change content of only that particular <div>.
Angular only renders where it detects changes.
AFAIK there is some room for improvments in *ngFor where it sometimes re-renders too many items when some are added/removed in the middle or the beginning but that is a known issue and will be fixed eventually.
From my comment below
In fact Angular doesn't need re-rendering optimization because it only does anything when bound values change and then it only changes the DOM where it is bound to the changed value. Angular doesn't have a virtual DOM that it needs to mirror to the actual DOM.
Angular2 is using zone.js for onChange rendering. Usually when a change is detected, it will trigger changeDetection that component and all the children, but you also can have control to change that, to force render some things or not render when you don't like angular2 behavior.
Here is a very good talk about how Angular2 change detection works : https://www.youtube.com/watch?v=CUxD91DWkGM
LE: Just to clarify, it will not re-render the component and all the children, it will detect and trigger changes for all of those, but will render only what is necessary.

Understanding how to use 3rd-party event handlers in Angular

I'm creating a simple Angular app that uses Ace editor (via ui-ace) for on-screen text editing. I want a handler to run when the cursor changes which will update a model object when the cursor is in a certain location. However, I also want to be able to click a button to move the cursor to a particular location (and also update the model object if necessary). Here's a jsfiddle that demonstrates the idea.
http://jsfiddle.net/fpzknzej/3/
The model object updates when the cursor is placed at the end of the word print on the second line. The problem is that the $scope.$apply() on line 30 will throw an in-progress error when the Move Cursor! button is pressed. However, without that line, the view bound to the model object will not update when the cursor is moved with the arrow keys.
My current understanding is that this is simply the wrong way to do this kind of thing and that I need to do something along the lines of wrapping the changeCursor event to operate solely in the angular world. However, I'm at a loss as to how to approach this task (custom directive seems to be the thing that comes up the most when searching for this type of thing?) and if there's a good resource for understanding how to interact with third-party event handlers within angular. Any pointers in the right direction would be appreciated.
Will try to make this as simple as possible.
All angular core event directives such as ng-click , ng-change etc will automatically call $apply() internally.
In your case with move cursor you start the digest with ng-click then have a bit of a circular issue where the external ace event triggered from within ng-click is also going to call $apply().
You really only want to call $apply() when events that change scope outside of the angular core need to update the view.
A short term workaround for your situation is to use $timeout() instead.
This will be added to the end of the current digest stack queue and will call $apply() once other digests are completed.
As for directive , yes, this code does belong in directive but you won't really be changing it's current structure ... just moving it to a different part of the app. For the short term that isn't going to change what is currently happening

How do you force Ember to rerender a component?

I have an Ember component that uses jQuery to add a canvas chart. When I change routes, I get a new model, but Ember's automatic rerendering does not work in this case. In fact, I don't know how to make the component code which adds the chart re-run at all. How can I do this?
Would it work better if it was a view?
Without looking at code, I'm going to guess based on your statement of the model changing.
Component Currently
uiSetup: function(){
// do magic here...
}.on('didInsertElement')
Component with observes
Assuming the model in the component is named model, this would fire every time the model changed as well as when the element was initially inserted into the page. You could also break it into two separate functions if you need it to act differently on model change vs element inserted first time.
uiSetup: function(){
// do magic here...
}.on('didInsertElement').observes('model')

Make DerbyJS only re-render certain DOM nodes

The way DerbyJS (http://derbyjs.com) seems to work at the moment is that it replaces everything in the body tag of the document whenever you click a link.
Is there anyway to say use the template, but replace the content inside #main-content with that instead of the whole body?
Navigation on the left is fixed and doesn't need the benefits of realtime interaction.
Why this is an issue is needing to run some Javascript on the page load to set the size of some containers based on the size of a users browser window, and once I click a link, this setup gets wiped and recreated, and of course, the Javascript doesn't run again, because the document itself hasn't refreshed, just the body.
This would also allow me to write nicer jQuery bindings for the most part, $('element').click(, rather than $('html').on('click','element', ...
Any thoughts, or is this a step too far for this framework at this point in time?
P.S. As I'm only just getting started with Derby, and realtime frameworks in general, maybe what I'm trying to do isn't best practice anyway? I chose Derby because I like the UX part of initial render on the server, then the rest in the client, but sharing routers, which reduces the duplication of code. Open to any better ways of achieving this.
There is no way to rerender part of body on page reload. Just whole body.
You can use app.enter hook to run js code after every page render.
No need to use jQuery bindings, use Derby bindings
I fully agree with Vladimir's answer, just trying to add something to it.
It should be possible to re-render part of the UI through transitional routes (http://derbyjs.com/#routes). In your case it seems like app.enter is the way to go though.

Categories

Resources