1

I've got this directive, and I'm trying to get it to reload the content it gets automatically. So far, not much luck. Care to help?

EDIT: I've tried the suggested answer but it won't work. I'm getting a $digestx10 error.

Everything works fine and is saved ok, the DOM just wont reload.

angular.module('mymodule').directive('chatContent',
    ["$compile",'localStorageService','loginService','peopleOnlineService', 
    function($compile, localStorageService, loginService, peopleOnlineService) {


var LoadData = function (data, userId) {
    var template = '';
    //localStorageService.IsUser(data.userId);

    if(localStorageService.IsUser(userId) === true){
       template = '<div class="feedItemChat"><div class="chatItem"><div class="chatMessage userChatMessage">{{content.chatMessage}}</div></div></div>';
    }else{
       template = '<div class="feedItemChat"><div class="chatItem"><div class="chatMessage otherChatMessage">{{content.chatMessage}}</div></div></div>';
    }
    return template;
};

var linker = function (scope, element) {

    var data = localStorageService.LoadDataLocal(localStorageService.CheckCorrectRoom(loginService.GetUser().userId, peopleOnlineService.GetParams().userId));

    scope.$watch(data, function(){
        element.html(LoadData(data,scope.content.userId)).show();
        $compile(element.contents())(scope);
    });
};

return {
    restrict: 'E',
    link: linker,
    scope: {
        content: '='
    }
};
}]);

I'm also wondering, how would one do to insert the html templates here, instead of stupidly long strings?

Valentin Roudge
  • 555
  • 4
  • 14
  • 1
    Well you only set the data variable once, no wonder it doesn't change. Put the `LoadDataLocal...` call into a function, and use that function as the first parameter of the watch (so you'll notice when something new was returned). – doldt Jul 02 '15 at 12:43
  • Care to write it? I'm trying but it does not work... – Valentin Roudge Jul 02 '15 at 12:48
  • Try to call `$watch` with third parameter `true`. (third parameter is for `objectEquality`) – Ivan Burnaev Jul 02 '15 at 12:56
  • Nah, too bad for speed, can't use that :/ – Valentin Roudge Jul 02 '15 at 12:58
  • 1
    element.html, $compile... -- u should avoid this. You just need usual directive with template. This localStorageService.IsUser(userId) should be just a scope variable, ng-if on it in template. – Petr Averyanov Jul 02 '15 at 13:20

2 Answers2

1

Note: I'm not tackling the problem of the DOM regeneration, just the incorrect $watch setup. To fix the digest issue, use a regular directive with a template attribute, as per Petr Averyanov's comment.

Instead of:

var data = localStorageService.LoadDataLocal(localStorageService.CheckCorrectRoom(loginService.GetUser().userId, peopleOnlineService.GetParams().userId));

scope.$watch(data, function(){
    /* ... */
});

Try:

scope.$watch(
    function(){
        return localStorageService.LoadDataLocal(localStorageService.CheckCorrectRoom(loginService.GetUser().userId, peopleOnlineService.GetParams().userId));
    }, 
    function(newData){
        /* this code will run when LoadDataLocal returns a different value*/
    });

(note that I've eliminated the data variable, and instead use the $watch newValue in LoadData.)

doldt
  • 4,466
  • 3
  • 21
  • 36
  • Are you sure you need to use compile? (I just copied that part) See Petr Averyanov's comment on your OP – doldt Jul 02 '15 at 14:40
1

Take this with a lot of salt, because I'm a noob and probably missing something...

I suspect you're fixing this in the wrong place. Is scope.content (in the outer scope) being set somewhere outside the Angular framework? If so, wrap scope.content =... in a $scope.$apply() to make the framework trigger any watches.

I think you don't need a $watch at all. You only need to use $watch when the change you need to trigger on is not referenced by the view. Every {{expression}} creates a watch on that expression.

Consider using a single template on the directive, and a "chatMessageClass" scope value that's included in an ng-class='...' in the template.

This minimizes work for you and the browser. Unless the rest of the code has some side-effects that are not evident, it all goes away.

var linker = function (scope, element) {
    scope.chatMessageClass = localStorageService.IsUser(scope.content.userId) ? 
        'userChatMessage' : 'otherChatMessage';
};

References: https://stackoverflow.com/a/15113029/685923 https://docs.angularjs.org/api/ng/directive/ngClass https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply

Community
  • 1
  • 1
Ed Staub
  • 15,480
  • 3
  • 61
  • 91