简体   繁体   中英

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

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.com/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 coming 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.com/script/ratings/images/star-empty-lg.png\" || \"http://www.codeproject.com/script/ratings/images/star-fill-lg.png\"}}' \
                    ng-Click='isolatedClick($index + 1)' \
                    ng-mouseenter='isolatedMouseHover($index + 1)' \
                    ng-mouseleave='isolatedMouseLeave($index + 1)'></img> \
            </div>",
    compile: 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.

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", compile: 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 }); }; } }; }); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM