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?

dominicglenn commented 10 years ago

I had this usecase just today actually.

By removing the following line: https://github.com/Pasvaz/bindonce/blob/master/bindonce.js#L170

And adding scope.bindonceController = bindonceController; to the following line: https://github.com/Pasvaz/bindonce/blob/master/bindonce.js#L188

I can call $scope.bindonceController.runBinders(); whenever I want to manually update the DOM. It would be really helpful if the code could be changed to support this.

Pasvaz commented 10 years ago

I'm sorry to let you wait, I have to push some updates, one of them includes the possibility to refresh the binders by user request, I think that would close this issue. I just need a bit of time (very rare thing right now for me) to clean it and push it.

dominicglenn commented 10 years ago

As a follow up to this; I'm guessing you're redoing a lot of the binders themselves here as well?

This like the bo-class binding, or the bo-if need modifying to add or remove elements in either case, not just do the positive effect or nothing? (I'm modifying it myself at the moment for this purpose exactly).

dominicglenn commented 10 years ago

Probably should; I'm just doing it at work atm and not sure how they'd feel about me doing that. But I'll change it on my own and try submit a PR.

rileylark commented 10 years ago

I also have this use case and suggested #50 . The API could be bo-rebind="whateverEventName". bo-rebind would listen $on $rootScope for whateverEventName and call bindonceController.runBinders() from @dominicglenn 's suggestion.

What do you all think? I'm going to work on this for my own project this week - would others like this api?

cc @Pasvaz

Pasvaz commented 10 years ago

Soon (I think this weekend) I'll publish two new directives, one is onewatcher and the other is bo-refresh-on, bo-refresh-on works exactly as you thought, it uses $on to listen on the channel declared in the attribute boRefreshOn and it runs the binders again. There is another way to achieve this result, in my experimental version I use also a setter to attach a refresh function to the scope, something like bo-refresh-with="refreshMe" so when you call $scope.refreshMe() bindonce runs the binders. If I can test it enough I could publish also bo-refresh-with, let's see.

rileylark commented 10 years ago

Perfect, that's exactly what I had in mind. Thanks! Let me know if you can use help either implementing or testing.

Pasvaz commented 10 years ago

thank you @rileylark, I appreciate it.

rileylark commented 10 years ago

I've got some huge $watches dragging me down and will need to start work on this soon. I'll be happy to offer a PR but don't want to redo work you've already done. @Pasvaz, do you have a branch in progress I can extend?

Meligy commented 10 years ago

Hey,

I love the idea of using events, and the idea of one watcher will make a huge appeal to many people.

Is this planned for any time soon?

Thanks a lot.

Pasvaz commented 10 years ago

I'll try to push my branch today, I'm sorry I can't do it as soon as I thought but I'm facing some deadlines.

rileylark commented 10 years ago

Hey, no worries, bindonce will save me a ton of time even without this feature. I'd appreciate seeing your branch for this issue even incomplete - I'm sure I'll at least learn about your architecture by seeing where you've started, and maybe I can even help finish the implementation!

Pasvaz commented 10 years ago

I pushed the branch rebind-debug https://github.com/Pasvaz/bindonce/blob/rebind-debug/bindonce.js , it works but it's still embrional, I need to test it extensively and to rewrite/clean the code. It uses the directive refresh-on="message" and one-watcher to refresh the binders. Feel free to play with it but don't use it in production.

Pasvaz commented 10 years ago

@rileylark it would be nice if you and the others could be test the rebind-debug branch extensively in order to evidentiate the bugs or memory leaks so I can change or confirm the way it works.

rileylark commented 10 years ago

Thanks a bunch - I played with it some this weekend and will have some serious time this week.

rileylark commented 10 years ago

Hah, I hadn't seen your last comment when I posted. Yes, I'll be happy to send you some of my tests. Is the new demo folder a good place to put new uses?

I didn't have angular set up in the same build setup that you have, so in my initial test page I just included it from the CDN.

Pasvaz commented 10 years ago

feel free to modify the demo as you want or to create new ones, that branch is supposed to be a work in progress so it is quite wild. At the moment, the first approach was to emulate angular and so to destruct and rebuild each bo-directive, the next step will be to improve it and reuse elements instead of removing them in order to speed up the whole process.

rileylark commented 10 years ago

@Pasvaz I just sent you a PR with a simple demo for bo-src and bo-style.

I am not sure that $broadcast and $emit are going to be sufficient for my project. I am making a slide editor, with infrequently-changing slides. Each slide is represented twice: once in a long list of all of the previews, and again in the main editor area.

screen shot 2014-02-18 at 7 43 09 pm

These are sibling scopes, and each of my slides should have its own rebind-on event, so I think I would have to $emit the change up to $rootScope and then $broadcast them back down. Blegh!

I have an alternative idea to using the $scopes as event busses: a complementary bindonceNotify service that I can inject into any required code. My client code can call bindonceNotify('customUpdateEventName'), and your rebind-on api can register on a back end of the service. That way we can ignore the $scopes altogether, avoid muddying up the $on handlers, and have a kind of private channel for rebind notifications.

What do you think? I can submit another PR for this if you think it's a worthwhile direction to explore.

rileylark commented 10 years ago

I went ahead and sketched it out in #60

bugwelle commented 10 years ago

Any further progress on rebind? :) I need this in an app I'm currently developing on :)

r3m0t commented 10 years ago

@archer96 I've made an Angular fork that does this, it is at:

https://github.com/r3m0t/angular.js/tree/digest_limit

It is built at:

https://github.com/r3m0t/bower-angular tag: 1.2.14-build.local+sha.1289c58 or v1.2.15-build.local+sha.9660989

An example is at:

https://gist.github.com/r3m0t/9271790

Watch out, it works very differently from pasvaz.bindonce. You can use ng- for everything instead of bo-, but inside the new-once directive all the directives are affected.

Pasvaz commented 10 years ago

guys I'll complete it asap, right now I'm busy dealing with some deadlines. @archer96 could you test the rebind branch, it's not complete but some feedback could surely help.

bugwelle commented 10 years ago

Hello,

I tried using that branch but there is one tiny "bug" that is annoying. Firstly my code:

<body ng-controller="MainCtrl">
<button ng-click="AddItem()">Add Item</button>
<button ng-click="RemoveFirstItem()">Remove First Item</button>
<ul>
    <li ng-show="!items">Items are not loaded, yet!</li>
    <li ng-show="items && !items.length">No items available!</li>
    <li bindonce="items" refresh-on="'rinfresca'" ng-repeat="item in items">
        <span bo-text="item.title"></span><br>
        <span bo-text="item.description"></span>
    </li>
</ul>
</body>

here my javsacript code:

var app = angular.module('bindoncedebug', ['pasvaz.bindonce']);

app.controller('MainCtrl', function ($scope, $q, $timeout) {

var count = 0;

$scope.AddItem = function () {
    $scope.items.push({
        title: 'Item ' + (++count),
        description: 'this is item number ' + count
    });
    $scope.$broadcast('rinfresca');
};

$scope.RemoveFirstItem = function () {
    $scope.items.shift();
    $scope.$broadcast('rinfresca');
};

$timeout(function () {
    $scope.items = [];
}, 1500)

$timeout(function () {
    $scope.items = [
        {
            title: 'Item 1',
            description: 'this is item number 1'
        },
        {
            title: 'Item 2',
            description: 'this is item number 2'
        },
        {
            title: 'Item 3',
            description: 'this is item number 3'
        }
    ];
    count = $scope.items.length;
}, 3000)

});

Rebind works well when putting refresh-onand bindonce on ul but when putting it on li it get following error when trying to remove an element:

TypeError: Object #<HTMLLIElement> has no method 'removeWatcher'
    at HTMLLIElement.ctrl.destroy (file:///Users/__myName__/github/local/bindonce/bindonce.js:176:12)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:27:208
    at r (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:7:386)
    at Object.$c.c [as handle] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:27:190)
    at cc (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:23:426)
    at Da (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:23:57)
    at r.remove (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:140:169)
    at Object.R.(anonymous function) [as remove] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:141:414)
    at Object.leave (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:143:309)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js:187:25 

I'd like to use refresh-on on list elements as seen in this example.

Regards, Andre

rajdeepg commented 10 years ago

I am getting the same error as Andre when using https://github.com/Pasvaz/bindonce/blob/rebind-debug/bindonce.js

TypeError: Object # has no method 'removeWatcher' at HTMLSpanElement.ctrl.destroy (https://mosaic-local.autodesk.com/lib/bower_components/angular-bindonce/bindonce.js:176:12) at HTMLSpanElement.bK.event.dispatch (https://staticfqa.staging.autodesk360beta.com/static/1.r343.2.r3/portal/script/core.js:26:43787) at HTMLSpanElement.ce.handle (https://staticfqa.staging.autodesk360beta.com/static/1.r343.2.r3/portal/script/core.js:26:39970) at Object.bK.event.trigger (https://staticfqa.staging.autodesk360beta.com/static/1.r343.2.r3/portal/script/core.js:26:42801) at bK.fn.extend.triggerHandler (https://staticfqa.staging.autodesk360beta.com/static/1.r343.2.r3/portal/script/core.js:26:51165) at removePatch as remove at https://mosaic-local.autodesk.com/lib/mosaic/angularjs/directives/infiniteScroll.dir.js:23:46 at wrappedCallback (https://mosaic-local.autodesk.com/lib/bower_components/angular/angular.js:11033:81) at https://mosaic-local.autodesk.com/lib/bower_components/angular/angular.js:11119:26 at Scope.$eval (https://mosaic-local.autodesk.com/lib/bower_components/angular/angular.js:12045:28)

Pasvaz, any idea on when you think you will have some time to look into this issue?

Thanks,

Raj

Pasvaz commented 10 years ago

@rajdeepg, please try it now

rajdeepg commented 10 years ago

Hi Pasvaz,

I just tried the latest and no longer getting the 'removeWatcher' error but also not seeing my ng-repeat update it self.

Here is the code I am using: <div class="card selectable" data-ng-class="{ checked: storageItem.checked, last: storageItem.lastColumn}" data-bindonce="storageItems" data-refresh-on="'refreshStorageItemList'" data-ng-repeat="storageItem in storageItems" data-index="{{$index}}" data-file-name="{{storageItem.Name}}" data-mo-drag data-mo-drop="dropFiles(draggedItemIndex, droppedItemIndex)" data-ng-drag-multiple="{{ storageItem.checked }}" data-mo-hover data-mo-menu="getStandardActions" data-mo-menu-for="storageItem" data-mo-menu-on="contextmenu" data-mo-menu-title="{{ i18n.Actions }}">

In My controller: var index = $scope.storageItems.indexOf(items[0]); $scope.storageItems[index].Name = items[0].Name; $scope.$broadcast('refreshStorageItemList'); $scope.$apply();

I am updating the Name field in the item and hoping that it refreshes in my grid but it is not refreshing? Is there something I am doing wrong?

If you can share some sample code on how this should work that will be great?

Thanks,

Raj

fidoboy commented 10 years ago

+1 :) Following this interesting feature...

dg192 commented 10 years ago

I'm using bo-text and bo-class, and can confirm refresh-on is working with 31148e7. Thanks, Pasvaz!

shansubra commented 10 years ago

I am trying to force refresh my table but its not refreshing. Can anyone please help me on how to do this?

HTML code:

<tbody bindonce="filteredItems" refresh-on="refreshTaskList" ng-repeat="task in filteredItems | orderBy:sortingOrder:reverse">
<tr>
 <td><span bo-bind="task.serviceTypeName | isEmpty : 'None'"></span></td>
  <td ><span bo-bind="task.percentageCompleted | isEmpty : 'Not Started'"></span></td>
</tr>
</tbody>

Controller code: $scope.$broadcast('refreshTaskList');

Please help me...

trevordixon commented 10 years ago

Exciting feature! Any help needed besides testing?

jtomaszewski commented 10 years ago

Yeah, that would be excellent! It would actually allow me to transform every single group of watchers to just one watcher. Tell us what you need and maybe we'll help you ;)

matias-sandell commented 10 years ago

Hi! Any idea when bo-refresh-on will be production ready?

thynctank commented 10 years ago

Awesome. Just came across this issue/feature while looking into other things... Can't wait for production-ready!

fidoboy commented 10 years ago

@dominicglenn : Your code for line 188: scope.bindonceController = bindonceController;seems to be wrong, scope is undefined. Can you verify it?

dominicglenn commented 10 years ago

@fidoboy I wrote that code ages ago when the bindonce code was very different from what it is now; I think they have a different way to of doing this now. If you still want to do it why don't you try binder.scope instead?

Meligy commented 10 years ago

Any idea where this feature has gone recently? Thanks a lot.

fidoboy commented 10 years ago

:smile: i'm counting the days… bind once directive is really amazing and having the rebind feature… it could be perfect!! I hope that this could be available soon…

thynctank commented 10 years ago

U know another way to sort of do this is to wrap your bindonce directive inside something else that will change, like a top-level object with infrequent watch triggers. When it does change, all the DOM children are refreshed, even if they are then "static" again after that.

maruf89 commented 10 years ago

+1

jtomaszewski commented 10 years ago

In the meantime - check out this: https://github.com/pcw216/angular-watch-when . Seems like to be a complete solution for that problem! Haven't got time yet to check that in a real app, but looks interesting.

johny commented 9 years ago

+1

Irto commented 9 years ago

+1

gindulis commented 9 years ago

+1

tateman66 commented 9 years ago

+1

nadavsinai commented 9 years ago

+1

dipcore commented 9 years ago

Take a look on this directive http://kent.doddsfamily.us/kcd-angular/#/kcd-recompile

dipcore commented 9 years ago

Here is my interpretation of 'kcd-recompile' directive (it uses angular 1.3 and broadcast events) http://jsbin.com/pigofojogo/2/edit?html,js,output

mica16 commented 9 years ago

Is this feature currently under development? or is it advised to try alternative like kdc-recompile? I tried this latter with Angular 1.3, can't manage to make it work when wrapping an ng-repeat... Thanks :)

trythrow commented 9 years ago

+1 What happen to this? any idea when it will be available? Did anyone succeed with a workaround?

jtomaszewski commented 9 years ago

Well, I'll just recommend you switching to angular 1.3 and to plugins mentioned above, they work perfectly.