Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

feature request: change events from ng-repeat, ng-switch, ng-options, directives with templateUrl #996

Closed
tbosch opened this issue May 29, 2012 · 23 comments

Comments

@tbosch
Copy link
Contributor

tbosch commented May 29, 2012

Hi,
for the jquery-mobile-angular-adapter, I have the following use case:
jQuery Mobile has a listview widget. That widget is applied to <ul> tags and, beneath other things, sets the rounded corners of contained <li>-items. I.e. the top most entry get rounded corners only at the top, entries in the middle don't get rounded corners, and the bottom entry gets rounded corners only at the bottom. After changes to the <li> elements, one needs to call the refresh function of the listview widget.

When ng-repeat is used to create the <li> entries in the list, I have to problem of detecting changes.

It would be great if angular could fire an event whenever ng-repeat, ng-switch, ng-options, or directives with a templateUrl change the dom, so that the adapter could afterwards refresh the corresponding container widgets like listview, checkboxradio (for ng-options).

Right now I have the following workaround:
I create additional directives that bind to the same elements as ng-repeat, ng-options, ng-switch, ..., watch the same value and trigger an event when the value changes. Especially for ng-options, this requires a lot of code duplication from the original angular directive....

I also noticed that ng-include already fires the $contentLoaded event. The same for the other directives would be great!

Thanks,
Tobias

@mhevery
Copy link
Contributor

mhevery commented May 29, 2012

This is a great use case, and i think we should support it. However, I don't think that the event system is the way to do it, since it would have a negative impact on performance. I was toying with the idea of monkey patching the jQuery to get the desired behavior, but I have not gotten very far with it.

I guess that for your use case it would be sufficient to know when the position of an item has changed.

@tbosch
Copy link
Contributor Author

tbosch commented May 29, 2012

Hello Miško,
yes, you are right, firing events whenever ng-repeat does something is not optimal for the performance.
So what about an ng-repeat Controller, to which other directives could register listeners (and also a ng-options controller and ng-switch controller)?

However, this would still not solve the problem when using directives with a templateUrl (they could also load content that would lead to a refresh of the parent widget). This could be solved if directives with a templateUrl would call a service like $compile (or a more specialized version), which I could track using a $provide.decorator.

For the jquery mobile plugin to work correctly, I would need the information when an item is created, destroyed and when the position changes.

I already had a version that listens for DOM changes using monkey patching in jQuery (essentially $.fn.domManip and $.fn.remove, see the old jQuery plugin live query http://docs.jquery.com/Plugins/livequery). However, ng-repeat knows when it changes the DOM, so it would be faster if it could directly inform listeners.

Tobias

@mhevery
Copy link
Contributor

mhevery commented May 29, 2012

I agree, we need the create, move, and delete information for animation, so
we will have to solve this issue soon.

On Tue, May 29, 2012 at 9:22 AM, Tobias Bosch <
reply@reply.github.com

wrote:

Hello Miško,
yes, you are right, firing events whenever ng-repeat does something is not
optimal for the performance.
So what about an ng-repeat Controller, to which other directives could
register listeners (and also a ng-options controller and ng-switch
controller)?

However, this would still not solve the problem when using directives with
a templateUrl (they could also load content that would lead to a refresh of
the parent widget). This could be solved if directives with a templateUrl
would call a service like $compile (or a more specialized version), which I
could track using a $provide.decorator.

For the jquery mobile plugin to work correctly, I would need the
information when an item is created, destroyed and when the position
changes.

I already had a version that listens for DOM changes using monkey patching
in jQuery (essentially $.fn.domManip and $.fn.remove, see the old jQuery
plugin live query http://docs.jquery.com/Plugins/livequery). However,
ng-repeat knows when it changes the DOM, so it would be faster if it could
directly inform listeners.

Tobias


Reply to this email directly or view it on GitHub:
#996 (comment)

@zyro23
Copy link

zyro23 commented Aug 5, 2012

any news on this one? or tigbro, did you find a viable workaround in the meantime?

@tbosch
Copy link
Contributor Author

tbosch commented Aug 7, 2012

Hi,
well, I duplicated the value watching code from ng-repeat, ... directives of angular into new directives that are connected to the same dom nodes, and which fire the needed event.
See e.g. here: https://github.com/tigbro/jquery-mobile-angular-adapter/blob/master/src/main/webapp/integration/ngRepeatPatch.js

Tobias

@wspringer
Copy link

I need it as well.

@harryxu
Copy link

harryxu commented Sep 6, 2012

I really need this feature.

@jimmy-collazos
Copy link

Hi,

I have a proposal for this this issues. Check solution for ngRepeat https://github.com/acido69/angular.js/compare/issue-996

Use:

App.Controller.Home = function($scope){

  $scope.$on('after-ngRepeat', function(event, stringCollectionName){
    console.log('fire after-ngRepeat!', event, stringCollectionName);
  });

  $scope.$on('before-ngRepeat', function(event, stringCollectionName){
    console.log('fire repeatBefore!', event, stringCollectionName);
  });

};

if have recommendation, please comment!

@petebacondarwin
Copy link
Member

What is the use case for these events?
Pete

On 14 November 2012 19:12, Jimmy Collazos notifications@github.com wrote:

Hi,

I have a proposal for this this issues. Check solution for ngRepeat
https://github.com/acido69/angular.js/compare/issue-996

Use:

App.Controller.Home = function($scope){

$scope.$on('after-ngRepeat', function(event){
console.log('fire after-ngRepeat!', event);
});

$scope.$on('before-ngRepeat', function(event){
console.log('fire repeatBefore!', event);
});
};

if have recommendation, please comment!


Reply to this email directly or view it on GitHubhttps://github.com//issues/996#issuecomment-10379363.

@jimmy-collazos
Copy link

Pete in my case need bind scroll in list (ng-repeat):

Template.html

    <div id="wrapper" class="offers scroller-wraper">
        <div class="scroller">
            <ul class="clearfix">
                <li ng-repeat="offer in offers" ng-click="openOffer()">
                    <img ng-src="{{offer.icon_src}}" alt="{{offer.name}}"/><br/>
                    a
                    <span>{{offer.name}}</span><br/>
                    <a href="#/coupon/{{offer.id}}">
                        <b>{{offer.price}}</b>
                    </a>
                </li>
            </ul>
        </div>
    </div>

In my controller trying that:

App.Controller.Home = function($scope, $route, $routeParams, $location){
  $scope.offers = Service.Coupon();
  new iScroll(document.querySelector('#wrapper'), {
      snap: true,
      momentum: false,
      hScrollbar: false
    });
};

of course, not found; because dispatch iScroll before the parse ng-repeat

now I use this cr*p ;(

App.Controller.Home = function($scope, $route, $routeParams, $location){
  $scope.offers = Service.Coupon();
  $scope.setScroll = function(){
    new iScroll(document.querySelector('#wrapper'), {
      snap: true,
      momentum: false,
      hScrollbar: false
    });
  };
  setTimeout($scope.setScroll, 200);
};

@tbosch
Copy link
Contributor Author

tbosch commented Nov 16, 2012

Well, my usecase is already stated above for the integration of jquery mobile and angular.

@michaelahlers
Copy link

+1

@ibspoof
Copy link

ibspoof commented Feb 11, 2013

+1, this would be very helpful in the long run.

Also @Acido69 this is another option that works without using timeout:

$scope.$watch(document.querySelector('#wrapper'), function() {
     $scope.setScroll();
});

@jonrimmer
Copy link

Well, animations has arrived, but instead of being built on a generic mechanism to hook into templating changes, it's just been hard-coded into all the directives. Are we supposed to misuse the animation events to do stuff like this now, even though is has nothing to do with animation?

@jimmy-collazos
Copy link

@ibspoof good idea!

@btford btford closed this as completed Aug 24, 2013
@btford
Copy link
Contributor

btford commented Aug 24, 2013

As part of our effort to clean out old issues, this issue is being automatically closed since it has been inactivite for over two months.

Please try the newest versions of Angular (1.0.8 and 1.2.0-rc.1), and if the issue persists, comment below so we can discuss it.

Thanks!

@core123
Copy link

core123 commented Nov 14, 2013

acido69 ..... please can u share ur application demo

i am working on Template.html in which i am using the ng-repeat with iscroll but it is not working

@core123
Copy link

core123 commented Nov 14, 2013

acido69 : if i dont use ng-repeat it is working fine with my demo app....... any clue regarding this thanks in advance

@core123
Copy link

core123 commented Nov 14, 2013

<script src="jquery-1.8.3.min.js" type="text/javascript"></script> <script src="jquery.mobile-1.3.2.min.js" type="text/javascript"></script> <script src="iscroll.js" type="text/javascript"></script> <script src="jquery.mobile.iscrollview.js" type="text/javascript"></script> <script src="listview.js" type="text/javascript"></script> <script src="angular.min.js" type="text/javascript"></script>
          <div data-role="header">
                 <h1>My TEST</h1>
          </div>

          <div data-iscroll="" data-role="content" id="wrapper" class="scrollable">
            <ul data-role="listview">
                     <li ng-repeat="list in lists">
                            <h3>{{list.text}}</h3>
                            <p>{{list.done}} With Angular JS</p>
                     </li>
                     <li>
                            <h3> Ecore-webapp </h3>
                            <p>This Item Is Not With Angular JS</p>
                    </li>
            </ul>
          </div>
    </div>

/**************************************************************************************************************************
js file
****************************************************************************************************************************/

function Todfunction TodoCtrl($scope)
{
var i=0;

    $scope.lists = [{text:'', done:''}];
    $(document).ready(function(){
            console.log("ready function");
            $scope.lists.pop();

            for(var i=0;i<50;i++)
            {
                    var songTitle  = "songTitle"  + i;
                    var songArtist = "songArtist" + i;
                    $scope.lists.push({text:songTitle, done:songArtist});
            }
            $scope.$apply();
var Scroller = new iScroll('wrapper');
$('#demo-page').bind('expand', function ()
{
    Scroller.refresh();
});
    });

}

Note : This code is working in chrome but not in web-kit please help me !!!!! tried all possible options

@jimmy-collazos
Copy link

@core123 You can try this dirty/fast solution:

<li ng-repeat="list in lists">
    <h3>{{list.text}}</h3>
    <p>{{list.done}} With Angular JS</p>
    {{ updateScroll($last) }}
</li>

.

// in controller
var Scroller = new iScroll('wrapper');
$scope.lists = [{text:'', done:''}];
$scope.updateScroll = function(isLast){
  if(isLast) Scroller.refresh()
}

example: http://plnkr.co/edit/10U3ai?p=preview check console

@core123
Copy link

core123 commented Nov 15, 2013

@Acido69 : thanks for ur help
i tried your solution ...... its updating the li which is not in derivative part ,which is in ng-repeat is not seen on screen

      <div data-iscroll="" data-role="content" id="wrapper" class="scrollable">
        <ul data-role="listview">
                 <li ng-repeat="list in lists"> /*this li part is not seen on screen*/
                        <h3>{{list.text}}</h3>
                        <p>{{list.done}} With Angular JS</p>
                 </li>/*this li part is not seen on screen*/
                 <li>/*this li part is visible on screen*/
                        <h3> Ecore-webapp </h3>
                        <p>This Item Is Not With Angular JS</p>
                </li>/*this li part is visible on screen*/
        </ul>
      </div>

My problem is that all li items are getting updated to view i guess and iscroll effect also seen but items are not visible !!!!

if i stop using iscroll creation then all items are visible (or) if i dont use ng-repeat also all items are visible but with ng-repeat + iscroll the derivative part is not visible !!!!

please help me

@adrianenriquez
Copy link
Contributor

Thanks for the dirty/fast solution @Acido69 !

@cfator
Copy link

cfator commented May 5, 2014

Really surprised there is no event based solution to hook into the lifecycle of ng-repeat.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests