Pasvaz / bindonce

Zero watches binding for AngularJs
2.73k stars 278 forks source link

rebind #42

Open romanesko opened 10 years ago

romanesko commented 10 years ago

Is it possible to force refresh of bindonce item?

JoaquimMadeira commented 9 years ago

Here is the 0.3.1 rebind-debug branch working for Angular 1.3, i have made a plunk.

http://plnkr.co/edit/wc4QNoB3nCpMdkWxrJlU?p=preview

dnozay commented 9 years ago

one workaround I was found somewhere: http://jsbin.com/tifukitesu/1/edit?html,js,output a directive that listens to an event and replaces the element after reapplying the template; the event is triggered by a $broadcast which could place where you need it.

floribon commented 9 years ago

kdc-recompile does what it says, i.e. recompile the whole HTML, which is pretty heavy. Instead, it would be way more performant to only recompute the values, such as ng-bind or ng-class. The directive referenced by @dnozay unfortunately relies on the same principle: recompiling the HTML.

I'm playing with ngWatchWhen right now, which seems promising, however it is actually increasing my number of watchers rather than decreasing it, so not convinced by it yet.

I've never used bindonce refresh-on but the idea sounds terrific. This is a big deal for the angular world and I'm surprised there's no real solution to it.

dnozay commented 9 years ago

how about maintaining a structure similiar to / copy of scope.$$watchers which only gets iterated through on certain event?

dipcore commented 9 years ago

You can use directives which recompile HTML, but use it with small HTML blocks only, or you get page blinking.

Let's say you have a list, so you can make:

<div ng-repeat="item in ::items" refresh-on-event="refresh-row-{{::$index}}">something</div>

And if you want to refresh a single row, just use: $scope.$broadcast('refresh-row-' + row_index); So basically split your page on small logical sections and refresh it per section.

floribon commented 9 years ago

I cannot. In my case I am manipulating a spreadsheet a-la-Excel. The table is fixed, but all values are dynamically recomputed as the user scrolls.

Only when he scrolls I want to recompute all these values. For all the other actions, their watchers are uselessly executed on every digest cycle. However when I actually scroll, all the cells are refreshed, which is way faster currently than recompiling the table.

I would bet that the compile phase is most of the time the bottleneck of a ng-repeat, unless some inner bindings are poorly designed.

dipcore commented 9 years ago

Maybe I didn't get you, but why you cannot recompile each cell? I mean to put in each cell of your table:

<span refresh-on-event="refresh-values">{{value[i][j]}}</span>

i,j - row and column numbers so you will need generate a static table structure using ng-repeat, and after just update (fill) array values[][] and broadcast an event "refresh-values" to refresh all cells?

floribon commented 9 years ago

I'm pretty sure it would be about the about the same performances to recompile every cell or all of them at once. And this cannot be faster than just refreshing the text.

I have set up a JSfiddle here: http://jsfiddle.net/2tzb11um/1/

Set the one-time binding and change HERE-kcd-recompile to kcd-recompile. There's some bug that I don't understand so I couldn't benchmark. However if you put kcd-recompile in the <table> element you will clearly see that it's way slower than regular bindings.

dipcore commented 9 years ago

Look on this "zero-watchers" example I made:http://jsbin.com/fuzanotaho/1/edit?html,js,output

ps "watchers" directive is just helper, do not use it in benchmarks

floribon commented 9 years ago

Thanks. Now use 50 rows and 50 columns in your example and compare the performances with my jsfiddle using watchers: it is a lot slower. Compiling means rewritting the DOM, vs just changing an attribute/text, shouldn't be a surprise that it is slower.

dipcore commented 9 years ago

Right, it's slow. I believe you need to use a custom directive to render each cell on incoming event: http://jsbin.com/konuzudada/1/edit but now I'm not sure if it's faster

dipcore commented 9 years ago

Just tried 150x50 elements, seems a bit faster, so you can use a service as a data provider for the directive, and broadcast refresh event with some parameters to get data from the service and render it.

floribon commented 9 years ago

Well for this example that may be ok but, let's be honest, a full jQuery, no-angular alternative would almost feel simpler. I don't want to reinvent angular, i.e. ng-class, ng-bind-html, etc.

The ideal solution would be to keep the one time bindings of angular 1.3+ (::) with some ng-refresh-on that would retrigger the watchers on this event. I believe that's why the rebind-debug branch is trying to do, as well as ngWatchWhen, but the latter don't seem to address the issue. Now I need to try bindonce, which would be the least to do since we are discussing on this directive.

JoaquimMadeira commented 9 years ago

floribon, why don't you use the rebind branch of bindonce? I've put online a version working for Angular 1.3 and an adjustment in the bo-class and bo-if directives.

http://plnkr.co/edit/wc4QNoB3nCpMdkWxrJlU?p=preview

kasperlewau commented 9 years ago

shameless 'commercial' ahead


I've been tinkering on a continuation of fast-bind[1] and fast-bind[2] for 1.3 and I feel fairly happy with the current state of things.

Have a look at bind-notifier if you need to refresh your binds but not recompile the entire DOM node.

Usage:

  <div bind-notifier="{ keyOne:expr1, keyTwo:expr2 }">
    <span>{{:keyOne:spanOneExpression}}</span>
    <span>{{:keyTwo:spanTwoExpression}}</span>
    <span>{{:keyOne:keyTwo:spanThreeExpression}}</span>
  </div>

Values can also be rebound by broadcasting ($$rebind:: + key).

note: I haven't tested this thoroughly in conjunction with ng-bind; any and all help/contributions/opinions would be greatly appreciated : )

note2: ng-bind + bind-notifier appears to work just fine, apart from a minor discrepency that resides in the angular core (https://github.com/angular/angular.js/issues/11716)