最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to re-render directive after a variable is changed? - Stack Overflow

programmeradmin7浏览0评论

I am using a directive for star rating. But the template the is loaded before data is loaded from HTTP. So i want to reload directive template after HTTP request is successful.

HTML

<html>

<head>
<script src=".4.5/angular.min.js" type="text/javascript"></script>
</head><body>


<div ng-app="myapp" ng-controller="movieCtrl">

<div star-rating rating="starRating" read-only="false" max-rating="10" click="click(param)" mouse-hover="mouseHover(param)"
        mouse-leave="mouseLeave(param)"></div>
        </div></body></html>

JS

var app = angular.module('myapp', []);
app.controller("movieCtrl", function($scope, $http) {

  $scope.starRating = 0;
  $scope.hoverRating = 0;


  $scope.mouseHover = function(param) {
    $scope.hoverRating1 = param;
  };

  $scope.mouseLeave = function(param) {

    $scope.hoverRating1 = param + '*';
  };
  //problem here
  //actual data ing via http
  //when value is changed i want to re-render below directive template
  setTimeout(function() {
    $scope.starRating = 5
  }, 1000);
});
app.directive('starRating', function() {
  return {
    scope: {
      rating: '=',
      maxRating: '@',
      readOnly: '@',
      click: "&",
      mouseHover: "&",
      mouseLeave: "&"
    },
    restrict: 'EA',
    template: "<div style='display: inline-block; margin: 0px; padding: 0px; cursor:pointer;' ng-repeat='idx in maxRatings track by $index'> \
                    <img ng-src='{{((hoverValue + _rating) <= $index) && \".png\" || \".png\"}}' \
                    ng-Click='isolatedClick($index + 1)' \
                    ng-mouseenter='isolatedMouseHover($index + 1)' \
                    ng-mouseleave='isolatedMouseLeave($index + 1)'></img> \
            </div>",
    pile: function(element, attrs) {
      if (!attrs.maxRating || (Number(attrs.maxRating) <= 0)) {
        attrs.maxRating = '5';
      };
    },
    controller: function($scope, $element, $attrs) {
      $scope.maxRatings = [];

      for (var i = 1; i <= $scope.maxRating; i++) {
        $scope.maxRatings.push({});
      };

      $scope._rating = $scope.rating;

      $scope.isolatedClick = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope.rating = $scope._rating = param;
        $scope.hoverValue = 0;
        $scope.click({
          param: param
        });
      };

      $scope.isolatedMouseHover = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = 0;
        $scope.hoverValue = param;
        $scope.mouseHover({
          param: param
        });
      };

      $scope.isolatedMouseLeave = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = $scope.rating;
        $scope.hoverValue = 0;
        $scope.mouseLeave({
          param: param
        });
      };
    }
  };
});

See Codepen for more info.

I am using a directive for star rating. But the template the is loaded before data is loaded from HTTP. So i want to reload directive template after HTTP request is successful.

HTML

<html>

<head>
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.4.5/angular.min.js" type="text/javascript"></script>
</head><body>


<div ng-app="myapp" ng-controller="movieCtrl">

<div star-rating rating="starRating" read-only="false" max-rating="10" click="click(param)" mouse-hover="mouseHover(param)"
        mouse-leave="mouseLeave(param)"></div>
        </div></body></html>

JS

var app = angular.module('myapp', []);
app.controller("movieCtrl", function($scope, $http) {

  $scope.starRating = 0;
  $scope.hoverRating = 0;


  $scope.mouseHover = function(param) {
    $scope.hoverRating1 = param;
  };

  $scope.mouseLeave = function(param) {

    $scope.hoverRating1 = param + '*';
  };
  //problem here
  //actual data ing via http
  //when value is changed i want to re-render below directive template
  setTimeout(function() {
    $scope.starRating = 5
  }, 1000);
});
app.directive('starRating', function() {
  return {
    scope: {
      rating: '=',
      maxRating: '@',
      readOnly: '@',
      click: "&",
      mouseHover: "&",
      mouseLeave: "&"
    },
    restrict: 'EA',
    template: "<div style='display: inline-block; margin: 0px; padding: 0px; cursor:pointer;' ng-repeat='idx in maxRatings track by $index'> \
                    <img ng-src='{{((hoverValue + _rating) <= $index) && \"http://www.codeproject./script/ratings/images/star-empty-lg.png\" || \"http://www.codeproject./script/ratings/images/star-fill-lg.png\"}}' \
                    ng-Click='isolatedClick($index + 1)' \
                    ng-mouseenter='isolatedMouseHover($index + 1)' \
                    ng-mouseleave='isolatedMouseLeave($index + 1)'></img> \
            </div>",
    pile: function(element, attrs) {
      if (!attrs.maxRating || (Number(attrs.maxRating) <= 0)) {
        attrs.maxRating = '5';
      };
    },
    controller: function($scope, $element, $attrs) {
      $scope.maxRatings = [];

      for (var i = 1; i <= $scope.maxRating; i++) {
        $scope.maxRatings.push({});
      };

      $scope._rating = $scope.rating;

      $scope.isolatedClick = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope.rating = $scope._rating = param;
        $scope.hoverValue = 0;
        $scope.click({
          param: param
        });
      };

      $scope.isolatedMouseHover = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = 0;
        $scope.hoverValue = param;
        $scope.mouseHover({
          param: param
        });
      };

      $scope.isolatedMouseLeave = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = $scope.rating;
        $scope.hoverValue = 0;
        $scope.mouseLeave({
          param: param
        });
      };
    }
  };
});

See Codepen for more info.

Share Improve this question asked Dec 23, 2015 at 16:16 AmitAmit 4,3002 gold badges30 silver badges38 bronze badges 2
  • 1 With directives, the controller is shared across all instances of the directive, making your code incorrect (unless everything has the same rating). You should tie the template to the scope.rating so that you get the benefit of the template updating when your rating changes – SoluableNonagon Commented Dec 23, 2015 at 16:20
  • @SoluableNonagon The directive is using an isolate scope, so $scope is different for each instance of the directive's controller. Though in this case there is nothing being done in the directive's controller that can't be done in the linking function. – georgeawg Commented Dec 23, 2015 at 17:06
Add a ment  | 

2 Answers 2

Reset to default 7

Here is a simple rating directive which uses stars, note that the logic is in the link function, rather than the controller.

function starRating() {
  return {
    restrict: 'EA',
    template:
      '<ul class="star-rating" ng-class="{readonly: readonly}">' +
         // see ng-repeat here? this will update when scope.stars is updated
      '  <li ng-repeat="star in stars" class="star" ng-class="{filled: star.filled}" ng-click="toggle($index)">' +
      '    <i class="fa fa-star"></i>' + // or &#9733
      '  </li>' +
      '</ul>',
    scope: {
      ratingValue: '=ngModel',
      max: '=?', // optional (default is 5)
      onRatingSelect: '&?', // callback
      readonly: '=?' // set whether this should be changeable or not
    },
    link: function(scope, element, attributes) {
      if (scope.max == undefined) {
        scope.max = 5;
      }
      function updateStars() { // update to rating value
        scope.stars = [];
        for (var i = 0; i < scope.max; i++) {
          scope.stars.push({
            filled: i < scope.ratingValue
          });
        }
      };
      scope.toggle = function(index) {
        if (scope.readonly == undefined || scope.readonly === false){
          scope.ratingValue = index + 1;
          scope.onRatingSelect({
            rating: index + 1
          });
        }
      };
      scope.$watch('ratingValue', function(oldValue, newValue) {
        if (newValue) {
          updateStars();
        }
      });
    }
  };
}

Use $scope.$apply() on setTimeout function and your code will work fine

also i have made simple modification to your code .. check here

  • i created a service to share data b/n controllers
  • added some $watch function to detect value change

var app = angular.module('myapp', []);
app.controller("movieCtrl", function($scope, $http, share) {

  $scope.starRating = 0;
  $scope.hoverRating = 0;

  $scope.mouseHover = function(param) {
    $scope.hoverRating1 = param;
  };

  $scope.mouseLeave = function(param) {
    $scope.hoverRating1 = param + '*';
  };
  $scope.$watch('starRating', function() {
    share.rating = $scope.starRating
  });
  setTimeout(function() {
    console.log('timeout set');
    $scope.starRating = 5;
    $scope.$apply();
  }, 1000);
});
app.factory('share', function() {
  var obj = {
    rating: 0
  }
  return obj;
});
app.directive('starRating', function() {
  return {
    scope: {
      rating: '=',
      maxRating: '@',
      readOnly: '@',
      click: "&",
      mouseHover: "&",
      mouseLeave: "&"
    },
    restrict: 'EA',
    templateUrl: "star1.html",
    pile: function(element, attrs) {
      if (!attrs.maxRating || (Number(attrs.maxRating) <= 0)) {
        attrs.maxRating = '5';
      };
    },
    controller: function($scope, $element, $attrs, share) {
      $scope.maxRatings = [];
      $scope.rating = share.rating;
      $scope.$watch('rating', function() {
        $scope._rating = share.rating;
      });
      for (var i = 1; i <= $scope.maxRating; i++) {
        $scope.maxRatings.push({});
      };

      $scope._rating = share.rating;

      $scope.isolatedClick = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope.rating = $scope._rating = param;
        $scope.hoverValue = 0;
        $scope.click({
          param: param
        });
      };

      $scope.isolatedMouseHover = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = 0;
        $scope.hoverValue = param;
        $scope.mouseHover({
          param: param
        });
      };

      $scope.isolatedMouseLeave = function(param) {
        if ($scope.readOnly == 'true') return;

        $scope._rating = $scope.rating;
        $scope.hoverValue = 0;
        $scope.mouseLeave({
          param: param
        });
      };
    }
  };
});

发布评论

评论列表(0)

  1. 暂无评论