3

I am trying to learn the Angular way of adding a DOM element with data returned from the service passing it to a directive by changing the scope variable from my controller.

My service

.factory('Poller', function($http,$q){
           return {
                poll : function(api){
                    var deferred = $q.defer();
                    $http.get(api).then(function (response) {
                            deferred.resolve(response.data);
                    });
                    return deferred.promise;
                }

            }
        });

My Controller

.controller('accordion',['$scope','Poller','$timeout',function($scope,Poller,$timeout){
$scope.newdata = null;

function Repeater ()  {
     $scope.$apply(function () {
     Poller.poll('api/getupdates')
       .then(function(data){
           $scope.newdata = data;                                   
            });
        });
     };
    $timeout(Repeater, 1000) ;             
    var timer = setInterval(Repeater, 11000);  

My Directive

.directive( 'newreading', function () {
  return {
    scope: {'newdata' : '='},
    templateURL : 'template\newreading.html',
    link: function ( scope, element, attrs ) {
      var el;

      scope.$watch('newdata', function () {

          console.log(scope.newdata);

      });
    }
  };
}); 

HTML //NOTE: this is done by ng-repeat

 <accordion-group id="Device 1">  
     <newreading ></newreading> 
 </accordion-group> 

 <accordion-group id="Device 2">  
     <newreading ></newreading> 
 </accordion-group>      

 <accordion-group id="Device3">  
     <newreading ></newreading> 
 </accordion-group>      

 <accordion-group id="Device4">  
     <newreading ></newreading> 
 </accordion-group> 

My Sample JSON

{
    "readings": [                    
            "id": "Device2",
            "T01": "3",
            "L02": "35"
    ]
}

Everything til here works fine, and I want to stay away from using jQuery at all (I know Angular has jQuery Lite)

My Question

Firstly, Is this the right approach to add an element to the DOM using Angular JS? If yes, how will I reuse this directive? Currently, scope.watch triggers the function 4 times (obviously!!).

I am too confused because I cannot find a simple way to trigger the right directive to add an element.

I have been through few parts of the documentation and found StackOverflow questions suggesting to compile and add elements, which I can do but I need to add the element in the required div.

Any help is much appreciated.

1 Answer 1

1

In your directive definition, you wrote scope: {'newdata' : '='}. What this will do is create an isolated scope where $scope.newdata is two-way bound to the attribute newdata of the newreading element.

So if your HTML doesn't say <newreading newdata="someVariableOnTheScope"></newreading> this doesn't make sense. I don't know on what scope your accordion controller operates, so I can't give you more specific advice.

It appears you don't need an extra directive for new readings since you're using the same template. You just want extra readings to be shown. So you should update the underlying model and your view will update itself. That's the magic of Angular.

The extra readings can be added as follows (assuming newData contains the new readings):

// create an object so you can lookup a device by id
var devicesById = _.indexBy($scope.data,'_id');
_.each(newData,function(device) {
  // add the new readings to the readings of the device with the correct id
  Array.prototype.push.apply(devicesById[device._id].readings,device.readings);
});

A plunkr: http://plnkr.co/edit/iKtmrToz4fkJ46bVfcjX

Some extra tips:

  • Don't write code in the link function if you don't need access to attrs or element. Do that in the controller of the directive
  • You only need to wrap your code in a $scope.$apply if you're doing things outside of the AngularJS scope. You're basically saying to Angular: I'm doing stuff in here that might have changed the DOM that you're aware of, sync again. This is mostly useful when also using other libraries (e.g. JQuery)
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the tips @Pieter . I understood your point for including variable in my HTML. I did this previously but an element is placed in the DOM without any data in it ,because the data is only received while app is running and there is new data from the server via Ajax polling.Also it needs add the element in the right div . I am not sure how will I do it. any suggestion ? FYI - 'accordion' is angular UI accordion github.com/angular-ui/bootstrap/tree/master/src/accordion
the attribute would only point to a variable. After a response is received, you can change still change the content of the object to which the variable points. I think I could help you better if you would create a plunkr or something similar
plnkr.co/edit/YSCjLRz8fJSbwedVAm5a?p=preview . newdata.json in this plunker will be updated with new data on polling. I am not sure how will I add it real time to the existing application . Thanks again @Pieter
Do you need a separate directive for new readings? Is it something like this (plnkr.co/edit/iKtmrToz4fkJ46bVfcjX) you're trying to accomplish?
You're a Legend !! This is exactly what I am trying to do . Can you briefly explain me the approach and if possible edit the answer so that I can tick it answered. Really appreciate you helping man :) @pieter

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.