0

I want to implement a like widget for different kind of documents. I tried to use a scope data to generate template html code, here is what I've done:

  angular.module('app.common')
    .directive('like',['favoritesResource','session','$q', like]);

  function like(favoritesResource, session, $q, $scope) {

    var news = $q.defer();

    function link(scope, el) {
      //console.log(scope);
      news.resolve(scope.vm.theNews);
    };

    function getTemplate(el, attrs) {
      loadNews().then(function(news) {
        console.log(news);
        favoritesResource.isLike(session.getCurrentUser.id, {docType: news.type, docId: news.id}, function(status) {
          if (status == 'like'){
            return '<button class="fa fa-heart" ng-click="vm.likeIt()">like</button>';
          }else {
            return '<button class="fa fa-heart-o" ng-click="vm.likeIt()">like</button>'
          }
        });
      });
    };

    function loadNews() {
      return news.promise;
    }

    return {
      link: link,
      restrict: 'E',
      template: getTemplate(),
      replace: true
    };
  }

I found the "news" object can be printed in the console, but the result html is <like></like>, not <button class="fa fa-heart" ng-click="vm.likeIt()">unlike</button> or <button class="fa fa-heart-o" ng-click="vm.likeIt()">like</button>, could anyone tell me what's wrong? Or do you have any suggestion to write such widget?

UPDATE:

This widget is within a controller used to show document content, here is my controller:

  angular
    .module('app.news')
    .controller('ReadNewsController', ReadNewsController);

  ReadNewsController.$inject = ['theNews', '$scope', 'favoritesResource', 'session'];
  function ReadNewsController(theNews, $scope, favoritesResource, session) {
    var vm = this;
    vm.theNews = theNews;

    vm.likeIt = function() {
      favoritesResource.like(session.getCurrentUser.id, {docType:theNews.type, docId: theNews.id});
    };

    vm.unlikeIt = function() {
      favoritesResource.disLike(session.getCurrentUser.id, {docType:theNews.type, docId: theNews.id});
    };

    vm.isLikeIt = function() {
      favoritesResource.isLike(session.getCurrentUser.id, {docType:theNews.type, docId: theNews.id});
    };
  }

and the routes:

var module = angular.module('app.news', ['ui.router', 'app.common', 'app.data']);

  module.config(appConfig);

  appConfig.$inject = ['$stateProvider'];

  function appConfig($stateProvider) {.state('app.readNews', {
        url: '/news/read/:id',
        templateUrl: 'app/modules/news/read/news.html',
        controller: 'ReadNewsController as vm',
        resolve: {
          theNews: function(newsResource, $stateParams) {
            return newsResource.get({id: $stateParams.id}).$promise.then(function(item){
              item.type = 'news'; //for 'like' directive
              return item;
            })
          }
        }
      })
2
  • The getTemplate() method returns before the function in the then() function gets executed since it is asynchronous. Commented Jan 4, 2016 at 4:43
  • the only difference I see is in class.. you should use ng-class value.. it can change it dynamically based on response of .then Commented Jan 4, 2016 at 4:57

1 Answer 1

1

Much much simpler to add conditional logic to the template using ng-class. Then load the data and set the scope variable isLiked

function like() {

    return {
      link: link,
      restrict: 'E',
      template: '<button class="fa" ng-class="{\'fa-heart\': isLiked,\'fa-heart-o\': !isLiked }" ng-click="vm.likeIt()">like</button>',
      replace: true
    };
  }

 function link(scope, el) {
  loadNews().then(function(news) {

    favoritesResource.isLike(session.getCurrentUser.id, {docType: news.type, docId: news.id}, function(status) {
        scope.isLiked = status === 'like'
    });
  });
};
Sign up to request clarification or add additional context in comments.

6 Comments

it should not work because isLiked is not exist when "template" is used.
that doesn't make sense ... you are going to use the same api call as you were to check which template and you can always set default to false
@eric2323223 The way the ng-class directive works is that it puts a $watch on the scope looking for isLiked. When isLiked changes (or becomes defined), the ng-class modifies the class of the element. @charlietfl is right. ng-class is the best way to do what you want.
I get this error using charlietfl's code: Error: [$parse:syntax] Syntax Error: Token 'ng' is an unexpected token at column 47 of the expression [{'fa-heart': isLiked,'fa-heart-o': !isLiked } ng-click=] starting at [ng-click=]. errors.angularjs.org/1.3.20/$parse/…
The reason of the error is it miss a ", it works now. Thank you guys.
|

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.