0

I have a legacy page that has a <input type="hidden" id="myId" value="somenumber"> that is populated with Jquery (legacy code) asynchronously after the page loads for the first time. On this page I am trying to have an angularjs directive. The only problem is I am trying to watch on #myId value so I can use it for my directive but the value changes and triggers the watcher once and it is empty - it doesn't happen again when it actually gets a numercal value from jquery. What am I doing wrong? I tried with ng-value,ng-model but still I get undefined for those attempts. Also it is not possible to introduce routing etc to get the id from there.. Thanks

Here is my directive:

angular.module("myModule")
.directive("myDir", function () {
    return {
        restrict: 'A',
        templateUrl: "template.html",
        scope : {},
        link: function (scope, element, attrs, ctrl) {
            scope.$watch(function () { return $("#myId").val() }, function (newVal) { ctrl.myId= newVal});
        },
        controllerAs: 'myCtrl'
    };

});
Michail Michailidis
  • 11,792
  • 6
  • 63
  • 106

1 Answers1

1

Angular is unaware of the jquery change (obviously). You can emit the data in a custom event in jQuery, capture that event in angular and rebroadcast it to your directive to get it the first time.

Here is a plunkr with it working: http://plnkr.co/edit/RTIzEudC7TktDTSdqWnQ It will update the binding on the page after jquery emits an event 5 seconds after page load

//emit in jquery
$(document).trigger('customEvent', data);

app.run(['$rootScope', function ($rootScope) {
    //capture jQuery events and re-broadcast them as angular events
                //events to capture
                var events = [
                    'customEvent'
                ];

                //To Use: $scope.$on('eventName', function(ngEvent, jqEvent, data)
                $(document).on(events.join(' '), function(e) {
                    $rootScope.$broadcast.apply($rootScope, [e.type].concat(Array.prototype.slice.call(arguments, 0)));
                });
});

//listen for it in directive
scope.$on('customEvent', function(){
    scope.$apply(function(){
        //do stuff here and angular will be aware of it
    });
});
Kevin F
  • 2,836
  • 2
  • 16
  • 21
  • +1 Ok but if I have let's say 20 directives as I will soon - I don't want each of them to be notified for distinct id changes.. Is there a better way? – Michail Michailidis May 28 '15 at 17:42
  • 1
    Not that I can think of. Generally you want to go all in with Angular so its not really built to function like this. Someone else might have a better solution, but this is how I handle random jQuery events that can't be moved to angular in projects. – Kevin F May 28 '15 at 17:44
  • the interesting part is if I do press a button and then have a function that just gets the id based on the $("myId") it works fine. It would be nice if watcher function was called many times till it has a value – Michail Michailidis May 28 '15 at 17:46
  • 1
    Yea, watchers are awesome until something happens that they are unaware of. Then the fix is never as easy as you'd like! – Kevin F May 28 '15 at 17:46
  • I tried it and it worked.. do you have an idea why I cannot see it in {{ myCtrl.myId}} in the template of the directive? – Michail Michailidis May 28 '15 at 18:27
  • it appears that whatever I do in the scope.$on() is not reflected in the templates... – Michail Michailidis May 28 '15 at 18:54
  • You need to apply the changes, I'll update the example – Kevin F May 28 '15 at 19:48
  • I tried applying but it said it was already in a $digest cycle - I will try your change – Michail Michailidis May 28 '15 at 20:07