AngularJS - 在服务获取带有滑块标记的 JSON 对象后无法初始化 jQuery 滑块

AngularJS - can't initialise jQuery Slider after Service GETs JSON object with slider Markup

我正在尝试将 Slick Slider Carousel 初始化到我的 AngularJS 应用程序.

我通过我创建的名为 slickSlider 的指令(代码如下)使它在一定程度上起作用。问题是只有当我将滑块的标记直接添加到 html 模板时它才有效,如果我从使用 promises/deferred 的外部服务获取标记仅在它是必填。

当我在 chrome 源面板上放置断点时,我看到 slickSlider 指令代码在 Controller 从服务获取数据之前被 运行,因此指令代码无效。

我在下面的代码片段中用我的应用程序的缩小版本复制了这个问题。

var app = angular.module('app', ['ngSanitize']);

app.controller('postsController', ['postsService', function (postsService) {
  var postsCtrl = this;
  postsCtrl.test = 'this is an expression from the controller'
  var promise = postsService.getPost(1);
    
    promise.then(function (data)
    {
        postsCtrl.data = data.data;
        
        // I can't access the API on SO so am replicating what I would get from it here.
        postsCtrl.slider = '<div class=\"slick-slider\">\n \n <div>Service Slide 1<\/div>\n \n <div>Service Slide 2<\/div>\n \n <div>Service Slide 3<\/div>\n \n <\/div>';
    });
}]);

app.service("postsService", function ($http, $q) {
    function getPost(postsId) {
      var deferred = $q.defer()
      var url = 'https://jsonplaceholder.typicode.com/albums/' + postsId;
      $http({
        method: 'GET', // GET OPTIONS
        cache: true,
        url: url,
        headers: {  
           'Content-Type': 'application/json;charset=UTF-8'
        }
      }).
      then(function(response) {
        //your code when success
        deferred.resolve(response);
      }, function(response) {
        //your code when fails
        deferred.reject(response);
      });
      return deferred.promise;
    }
    this.getPost = getPost;
});

app.directive('slickSlider',function(){
 return {
   restrict: 'C',
    link: function(scope, elem, attrs) {
      $(elem).slick({
            // settings
      }); 
    }
  }
});
body {
  font-family: sans-serif;
  font-size: 14px;  
}
h1 {
  font-size: 15px;
  margin: 20px 0 2px;
}
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.9/angular-sanitize.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>
<body ng-app="app" ng-controller="postsController as postsCtrl">
 Controller is working... &nbsp; <i>{{postsCtrl.test}}</i> <br />
   Service is working...  &nbsp; <i>{{postsCtrl.data.title}}</i>
 <h1>Slider Carousel markup from simple HTML</h1>
 <div class="slick-slider">
  <div>HTML Slide 1</div>
  <div>HTML Slide 2</div>
  <div>HTML Slide 3</div>
 </div>
 <h1>Slider Carousel markup from expression supplied by Service</h1>
    <div ng-bind-html="postsCtrl.slider"></div>     
</body>

更新

我尝试在我的指令中使用 $timeout,但没有成功!

app.directive('slickSlider',function($timeout){
 return {
   restrict: 'C',
    link: function(scope, elem, attrs) {
      $timeout(function () {
        $(elem).slick({
            // settings
        }); 
      });
    }
  }
});

您需要在 postsCtrl.slider 值更改后重新编译元素。

var app = angular.module('app', ['ngSanitize']);

app.controller('postsController', ['postsService',
  function(postsService) {
    var postsCtrl = this;
    postsCtrl.test = 'this is an expression from the controller'
    var promise = postsService.getPost(1);

    promise.then(function(data) {
      postsCtrl.data = data.data;

      // I can't access the API on SO so am replicating what I would get from it here.
      postsCtrl.slider = '<div class=\"slick-slider\">\n \n <div>Service Slide 1<\/div>\n \n <div>Service Slide 2<\/div>\n \n <div>Service Slide 3<\/div>\n \n <\/div>';
    });
  }
]);

app.service("postsService", function($http, $q) {
  function getPost(postsId) {
    var deferred = $q.defer()
    var url = 'https://jsonplaceholder.typicode.com/albums/' + postsId;
    $http({
      method: 'GET', // GET OPTIONS
      cache: true,
      url: url,
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      }
    }).
    then(function(response) {
      //your code when success
      deferred.resolve(response);
    }, function(response) {
      //your code when fails
      deferred.reject(response);
    });
    return deferred.promise;
  }
  this.getPost = getPost;
});

app.directive('slickSliderContent', function($compile) {
  return {
    restrict: 'A',
    replace: true,
    link: function(scope, elem, attrs) {
      scope.$watch(attrs.slickSliderContent, function(html) {
          elem[0].innerHTML = html;
          $compile(elem.contents())(scope);
      });
    }
  }
});

app.directive('slickSlider', function() {
  return {
    restrict: 'C',
    link: function(scope, elem, attrs) {
      $(elem).slick({
        // settings
      });
    }
  }
});
body {
  font-family: sans-serif;
  font-size: 14px;
}
h1 {
  font-size: 15px;
  margin: 20px 0 2px;
}
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.9/angular-sanitize.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.slick/1.6.0/slick.min.js"></script>

<body ng-app="app" ng-controller="postsController as postsCtrl">

  <div class="slick-slider" slick-slider-content="postsCtrl.slider"></div>
</body>