Angular2 OnPush change detection and ngFor - performance

I have a parent component that displays a list of child components using ngFor. I noticed that performance gets really bad with increasing number of children so I have changed both to OnPush change detection strategy.
That helped a lot, but there are still few scenarios when it slows down and I can see thats due to change detection being executed for each of the children unnecessarily.
One example is when there is a click event inside the child component - even though no inputs is changed and its just triggering an animation, for some reason the change detection is being executed for parent component and as a result for each child component as well (even though the model behind ngFor doesnt change at all and its a OnPush strategy...). I would have thought that this kind of "isolated" event should only trigger change detection in that particular child component and not propagate up (I have actually tried event.stopPropagation() and event.preventDefault() with no success).
So I was wondering two things:
1) is there any way of having more control for what events change detection actually runs and whether it triggers the parent component change detecion as well?
2) is using "translate" pipes quite a lot in each child component (from ng2translate) could slow the application/change detection a lot?
Sample plunkr below to show what the problem is. Basically if I click on any of the item in ngFor list, it kicks of change detection for every single child rather than only the affected one and I was wondering if there is any way of suppressing that.
https://plnkr.co/edit/mD8HCbwq0cEwPt7itpCf

1) You can use ChangeDetectorRef.detach()
https://angular.io/docs/js/latest/api/core/index/ChangeDetectorRef-class.html#!#detach-anchor
Detaches the change detector from the change detector tree.
The detached change detector will not be checked until it is reattached.
This can also be used in combination with ChangeDetectorRef to implement local change detection checks.
2) pipes (if they are pure, which is the default) are only called when piped values or parameters change, therefore there is no performance disadvantage.

Related

Keep Business Process Display State as collapsed

I am trying to keep the business process flow display state as collapsed.
I am currently making it collapsed at addOnStageChange
Xrm.Page.ui.process.setDisplayState('collapsed');
It works fine on Stage Change for me. But if I click on the same stage twice which means stage is not changing then the BPF gets expanded. I am assuming if it is the default behavior.
How can I prevent it from expanding permanently?
If you are using Unified Interface it will be collapsed by defualt.
But if you are using legacy web client.
Add onload event on your From (for ex.Opportunity entity) and add below lines of code.
function collapseOpporBusinessProcess(){setTimeout(collapseOpporBusinessProcessDelay,300)}
function collapseOpporBusinessProcessDelay(){Xrm.Page.ui.process!=null&&Xrm.Page.ui.process.setDisplayState(“collapsed”)}
BPF cannot be collapsed always in classic UI, but possible in UCI like popout behavior or flyout without expanding. It needs some unsupported DOM manipulation in classic UI to nullify the click event of stage chevron or simply user training not to click it at all. Or better create a similar UI using webresource if you want.
It fails the original purpose, and re-purposing the BPF raise these kind of questions. If you have built the necessary business logic already in some other means - then custom UI is better choice rather than bending the BPF.
BPF is for guided process advancement, we can add attributes/entities as steps to move forward and enforce the field value requirements for reaching next level. I know some clients use them as tabs, some use them as just chevron tracker, so they don't want to waste the real estate under the BPF as they don't need any fields under the stages.

NSBrowser / NSTreeController with async data

I have a NSBrowser that needs to display data that comes from a REST API. Sometimes this API takes a while to return results, so it would be nice to handle the network traffic in the background (lazy fetching). Sometimes a subtree needs to be refresh to reflect server side changes.
I've tried two different approaches:
Using NSBrowserDelegate. When [browserDelegate browser:child:ofItem:] or similar function ends up requesting data that is not yet loaded, I return 0 count and kick off background processing. When the data becomes available I have the columns reloaded (not very efficient, messes with the user's selection as new data comes in).
Using NSTreeController. I got this to work well using a blocking/synchronous approach. However, whenever I update the model, NSBrowser resets the tree and moves the selection up to the parent. I've tried [obj mutableArrayValueForKey] approach. I've tried the [treecontroller insertObject:atArrangedObjectIndexPath:] approach. I've toggled "preserve selections" flag. I've toggled "select on insert". No matter what I do, NSBrowser doesn't want to cleanly update only the relevant subtree.
Bottom line: what is the best practice for asynchronously loading data into an NSBrowser?

Needing to select the item twice in the treeview before being able to activate combo box

I am drawing the GUI using GTK+ with PyGTK.
I've created a ComboBox within a TreeView. But the problem is that when I first click an item, the dropdown arrow is insensitive (grayed-out). I had to click another item and then return to the item again to for the dropdown arrow to be sensitive again.
Is this standard for ComboBox in TreeView? If you have a fix in any other language, I can accept it as well.
An example can be found here.
He is facing some other issues but his code demonstrates the problem as well.
The problem with the code you are referring to above seems to be that the ComboBox actually only has 1 element when you start editing, which makes drop-down feature useless (and hence inactive). To make it behave as I suspect you wish, all you have to do is use another signal to execute self.populate_combo. I added two lines after the treeview was created to make it work:
treeview = gtk.TreeView(liststore_hardware)
sel = treeview.get_selection()
sel.connect("changed", self.populate_combo)
That is, I made the changed selection cause population of the Combos, which implied that they had more than one element in them when control was returned to the main-loop. And hence drop-down worked.
I also commented out the previous editing-started signal since it added nothing with the current structure of the program.
window.connect("destroy", lambda w: gtk.main_quit())
#self.cellrenderer_combo.connect("editing-started", self.populate_combo)
self.cellrenderer_combo.connect("edited", self.combo_changed, liststore_hardware)
Edit:
On second thought, the model is a None after __init__ has been run and not 1-length per row as I wrote above, which makes the lack of dropdown-features even more reasonable.
Comment:
The code you referred to and my change to it are both only rational if changing rows (or editing) causes a drastic need to rewrite the ListStore. I'm not really sure what type of scenario would demand that. If, on the other hand, the contents of the TreeView and the ComoBox' ListStore varies as a result of a search-action or filtering done else-where, then that search, rather than the change of rows should invoke populate_combo.
So an alternative solution in the scope of the code at hand, my suggested event above can also be commented out and a simple
self.populate_combo()
be added as the last line of the init function.
Further, should there be a need to re-populate the combos during the run of the app, I would suggest that the current ListStore is modified rather than creating a new one each time, if the changes are not expected to be major (in which case make a new is probably fastest and simplest).

ContentPresenter.Loaded not raised when the control is initially created as collapsed

Perhaps hoping in a miracle, but let's try :-)
MyControl derives from Control. Its ControlTemplate contains
<ContentPresenter ContentTemplate="{TemplateBinding EditorTemplate}"/>
(Other details are omitted.)
Derived controls supply suitable EditorTemplate. For example MyTextControl specifies template consisting of a TextBox. (With proper bindings, of course.)
I won't describe what works (most scenarios), but what does not:
A collapsed MyTextControl instance is created. Later on this control is made visible. Here is what happens:
MyTextControl instance created, set to Collapsed
MyTextControl.Loaded event: At this moment the visual tree contains MyTextControl with no children.
In the Loaded handler I call ApplyTemplate(). In turn the visual tree is modified to MyTextControl -> ContentPresenter. That's all, no more children.
Stil in Loaded handler, I assign Loaded handler to the ContentPresenter.
Sometimes later the control is made visible. Its visual tree gets populated by TextBox internals: Border -> ContentControl -> ContentPresenter -> internal TextBoxView. In other words the control just works.
The problem is that the ContentPresenter Loaded handler was not called, i.e. I am not able to identify the moment when the control is ready.
I tried an alternative solution, i.e. instead of forcing ApplyTemplate() I simply waited in MyControl.OnApplyTemplate(). The sequence:
MyTextControl instance created, set to Collapsed
In the Loaded handler the visual tree contains MyTextControl with no children.
The control is made visible.
In OnApplyTemplate() the visual tree is MyTextControl->ContentPresenter.
Stil in OnApplyTemplate(), I assign Loaded handler to the ContentPresenter.
The rest is as before. The visual tree is populated by TextBox internals (the control works), but the above handler gets not called.
Does anybody know a way how to identify the moment when the control is fully loaded?
Note that I did the above with several other MyControl-derived controls. For each of them one of the above scenarios worked (sometimes one, sometimes another), but the TextBox-based control is the first one where I am not able to identify moment of loading.
Also note that this problem does not happen when the control is visible for all the time.
Ok, I'll answer myself. My current conclusion after 1 day and dozens of tests is that Loaded event is for birds. It happens on various stages of the control life cycle and in case of composite controls there is no warranty that the control is fully functional. In some cases it might be not fired at all.
Forcing template building by calling ApplyTemplate() is no solution either as in some cases it may result in building partial control tree.
OnApplyTemplate suffers similar problems - it might be called when only partial control tree is built.
After acknowledging the above statements I decided to give a try to LayoutUpdated event. I set up the handler in OnApplyTemplate() (I tried to use latest possible moment) and investigated the control tree. As a first approximation it seems to be sufficient to check if the ContentPresenter has children. If so, we'll say that the control is loaded and unregister LayoutUpdated handler. A more sofisticated test could be used, but the trivial one I just described is working for wide range of controls.
Originally I was afraid that the LayoutUpdated solution will be inefficient, but it looks like (using the described organization) the first handler call is exactly the place when the control is "loaded".

Tetris and pretty graphics

Say you're building a Tetris game. As any proper programmer, you have your view logic on one side, and your business logic on the other side; probably a full-on MVC going on.
When the model sends its update(), the view redraws itself, as expected.
But then... if you wanted to add, say, an animation to vanish a line, how would you implement that in the view?
Make any assumptions you want---excepting that "Everything is properly encapsulated".
Personally, I would separate draw the screen as often as possible, even if there was no update of the block position. So I would have a loop somewhere with an "update" and a "render" part. Update plays the ball to the logic which does or does not any update of positions and/or block removal. Render plays the ball to the graphics part, which draws the blocks where they should be.
Now if there are lines to erase, the logic knows and can mark those lines to be removed. I assume here, that every piece consists of 4 single blocks and any of these blocks is a single object. Now when this block has the "die"-flag set, you may take some render-parts to vanish the block (let's say, 500ms to explode). After this time, the object may be disposed and the block a line above falls down. Why 500ms? Well, you should definitely use time-based movement as this keeps the game speed the same on different computers.
Btw, there are already so called game engines which provide such an update-render-loop. For example XNA, if you go the .NET line. You may also code your own engine but beware, it's not an easy task and it's very time consuming. I did this once and don't expect it to be an engine like the Source Engine ;-)
Most games execute a loop that constantly redraws the view of the game as fast as possible, rather than waiting for a change in the model state and then refreshing the view.
If you like the model view pattern, then it might work well for the view to continue to draw some types of objects after they are removed from the model, fading them out over a few milliseconds.
Another approach would be to combine class MVC with something like differential execution - the 'view' is a model of what is presented, but the drawing code compares the stream of events the 'view' creates with the stream from the previous rendering. So if in one stream there's a line, and the next there isn't, the drawing code can animate the difference. This allows the drawing to be abstracted away from the view . Frequently the 'view' in MVC is a collection of widgets, rather than being something which draws the display directly, so you end up with nested MVC hierarchies anyway: the application is MVC ( data model, view objects, app controller ), where the view object has a collection of widgets each of which is MVC ( widget state (eg button pressed ), look and feel/toolkit binding, mapping of toolkit events -> widget state ).
I've often wondered this myself.
My own thoughts have been along this line:
1) The view is given the state of the blocks (shape, yada-yada), but with extra "transitional" data:
2) The fact that a line must be removed is encoded in the state, NOT computed in the view.
3) The view knows how to draw transitions now:
No change: state is the same for this particular block
Change from "falling" to "locked": state is "locked in" (by a dropping block)
Change from "locked" to "remove": state is "removed" (by a line completion)
Change from "falling" to "remove": state is "removed", but old state was "falling"
Its interesting to think of a game as an MVC. Thats a perspective I've never taken (for some odd reason), but definitely an intriguing one that makes a lot of sense. Assuming you do implement your Tetris game with an MVC, I think there are two things you might want to take into account in regards to communication between your controller and your view: There is state, and there are events.
Your controller is obviously the central point of interaction for the user. When they issue keyboard commands, your controller will interpret them, and make the appropriate state adjustments. However, sometimes the game will enter a state that coincides with a particular event...such as filling a line with blocks that should now be removed.
Scoregraphic has given you a great foundation. Your view should operate on a fixed cycle to maintain consistent speed across computers. But in addition to updating the screen to render new state, it should also have a queue of events that it can perform animations in response to. In the case of filling lines in Tetris, your controller could issue strongly typed event objects that derive from some kind of base event type into the view event queue, which could then be used by the view to perform the appropriate animated responses.

Resources