【问题标题】:AngularJS application: unable to update $indexAngularJS 应用程序:无法更新 $index
【发布时间】:2019-11-27 08:11:18
【问题描述】:

我正在使用 Giphy.com api 在 AngularJS 1.6 中开发一个应用程序。

有一个Plunker HERE

我遍历来自https://api.giphy.com/v1/gifs/trending?api_key=myApyKey 的“giphys”数组并将它们显示到 Bootstrap 4 卡片中。

有一个查看单个 giphy 功能。在控制器中我有:

// Create controller for the "giphyApp" module
app.controller("giphyCtrl", ["$scope", "$http", "$filter", "$timeout", function($scope, $http, $filter, $timeout) {
  var url = "https://api.giphy.com/v1/gifs/trending?api_key=PTZrBlrq8h2KUsRMeBuExZ5nHyn7dzS0&limit=120&rating=G";
  $scope.giphyList = [];
  $scope.search = "";
  $scope.filterList = function() {
    var oldList = $scope.giphyList || [];
    $scope.giphyList = $filter('filter')($scope.giphys, $scope.search);
    if (oldList.length != 0) {
      $scope.pageNum = 1;
      $scope.startAt = 0;
    };
    $scope.itemsCount = $scope.giphyList.length;
    $scope.pageMax = Math.ceil($scope.itemsCount / $scope.perPage);
  };

  $http.get(url)
  .then(function(data) {
      // giphy arary
      $scope.giphys = data.data.data;
      $scope.filterList();
      console.log($scope.giphys);

      // Paginate
      $scope.pageNum = 1;
      $scope.perPage = 24;
      $scope.startAt = 0;
      $scope.filterList();

      $scope.currentPage = function(index) {
        $("html, body").animate({
          scrollTop: 0
        }, 500);
        $timeout( function(){
          $scope.pageNum = index + 1;
          $scope.startAt = index * $scope.perPage;
        },0);
      };

      $scope.prevPage = function() {
        if ($scope.pageNum > 1) {
          $scope.pageNum = $scope.pageNum - 1;
          $scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
        }
      };

      $scope.nextPage = function() {
        if ($scope.pageNum < $scope.pageMax) {
          $scope.pageNum = $scope.pageNum + 1;
          $scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
        }
      };

      $scope.selectedIndex = null;
      $scope.selectedGiphy = null;

      $scope.fetchSinglegGiphy = function(giphy, index) {
        console.log(index);
        $scope.selectedIndex = index;
        $scope.selectedGiphy = giphy;
      }
    });
}]);

网格

<div class="row grid" ng-if="giphyList.length > 0">
  <div data-ng-repeat="giphy in giphyList | limitTo : perPage : startAt" 
       class="col-xs-12 col-sm-6 col-lg-4 col-xl-3 d-flex mb-4">
    <div class="giphy d-flex flex-column w-100">
      <div class="thumbnail pb-2 text-center" data-toggle="modal"
           data-target="#giphyModal"
           ng-click="fetchSinglegGiphy(giphy, $index)">
        <img ng-src="{{giphy.images.downsized.url}}" class="img-fluid">
      </div>
      <div class="text mt-auto">
        <p class="m-0 meta">{{giphy.import_datetime | dateParse | date : "MMMM dd y" }}</p>
        <p class="rating m-0">
          <i class="fa fa-star" aria-hidden="true"></i> {{giphy.rating | capitalize}}
        </p>
        <ul class="list-unstyled mb-0 text-center">
          <li ng-if="giphy.username != ''" class="text-muted">{{giphy.type | capitalize}} file uploaded by
            <br><strong>{{giphy.username | capitalize }}</strong>
          </li>
          <li ng-if="giphy.username == ''" class="text-muted">{{giphy.type | capitalize}} file uploaded by
            <br> <strong>Unknown</strong>
          </li>
          <li class="h6">{{giphy.title | titlecase }}</li>
        </ul>
      </div>
    </div>
  </div>
</div>

模态

<div class="modal fade" id="giphyModal">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title h-3">{{selectedGiphy.title | titlecase }}</h4>
        <button type="button" class="close" data-dismiss="modal">
        <span>&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <div class="row">
          <div class="col-12">
            <div class="image image text-center">
              <img ng-src="{{selectedGiphy.images.original.url}}"
                   alt="{{selectedGiphy.title }}" class="img-fluid">
            </div>
          </div>
        </div>
      </div>
      <div class="modal-footer justify-content-between">
        <div class="text-muted">Image ID: {{selectedGiphy.id}}</div>
        <div class="btn-group btn-group-sm">
          <button type="button" class="btn btn-success" data-dismiss="modal">
             <i class="fa fa-times-circle"></i> Close
          </button>
        </div>
      </div>
    </div>
  </div>
</div>

应用程序的这部分工作正常。

我曾期望能够轻松地将 下一个和上一个 giphy 添加到上面的模式中:

<div class="controls text-center">
    <a href="#" ng-click="fetchSinglegGiphy(giphy, $index = $index - 1)" class="left">
      <i class="fa fa-chevron-left"></i>
    </a>
    <a href="#" ng-click="fetchSinglegGiphy(giphy, $index = $index + 1)" class="right">
      <i class="fa fa-chevron-right"></i>
    </a>
</div>

令我惊讶的是,这不起作用。当我单击任何一个控件时,GIF 文件保持不变,但模式中的所有文本都消失了。

问题:

  1. 这种方法有什么问题?
  2. 您认为可行的替代方案吗?

【问题讨论】:

  • 你可以尝试用 $index - 1 代替 $index = $index - 1 吗?
  • @Giovanni 我做到了。结果是一样的。
  • $index 是由 ng-repeat 创建/管理的,你不应该尝试编辑它。
  • 也许您可以将索引保存在本地存储或其他东西中?
  • 您的第二个代码块是否在ng-repeat 之外?你不能在它之外使用$index

标签: javascript angularjs bootstrap-4


【解决方案1】:

index.html

<div class="modal fade" id="giphyModal">
   <div class="modal-dialog">
      <div class="modal-content">
         <div class="controls text-center">
            <a href="#" ng-click="fetchSinglegGiphyModal('prev')" class="left"><i class="fa fa-chevron-left"></i></a>
            <a href="#" ng-click="fetchSinglegGiphyModal('next')" class="right"><i class="fa fa-chevron-right"></i></a>
         </div>
         <div class="modal-header">
            <h4 class="modal-title h-3">
               {{ selectedGiphy.title | capitalize }}
            </h4>
            <button type="button" class="close" data-dismiss="modal">
               <span>&times;</span>
            </button>
         </div>
         <div class="modal-body">
            <div class="row">
               <div class="col-12">
                  <div class="image image text-center">
                     <img ng-src="{{ selectedGiphy.images.original.url }}" alt="{{ selectedGiphy.title }}" class="img-fluid" image-on-load ng-hide="modalImageLoading" />
                     <div class="spinner-border" ng-if="modalImageLoading"></div>
                  </div>
               </div>
            </div>
         </div>
         <div class="modal-footer justify-content-between">
            <div class="text-muted">
               Image ID: {{ selectedGiphy.id }}
            </div>
            <div class="btn-group btn-group-sm">
               <button type="button" class="btn btn-success" data-dismiss="modal">
                  <i class="fa fa-times-circle"></i> Close
               </button>
            </div>
         </div>
      </div>
   </div>
</div>

修改:

<a href="#" ng-click="fetchSinglegGiphyModal('prev')" class="left"><i class="fa fa-chevron-left"></i></a>
<a href="#" ng-click="fetchSinglegGiphyModal('next')" class="right"><i class="fa fa-chevron-right"></i></a>

fetchSinglegGiphyModal 根据作用于我们在函数中传递的参数 prevnext 值的条件来处理上一个和下一个 Giphy

我还添加了以下代码来引入引导程序附带的加载程序,以指示GIF图像正在后台加载。

<div class="image image text-center">
   <img ng-src="{{ selectedGiphy.images.original.url }}" alt="{{ selectedGiphy.title }}" class="img-fluid" image-on-load ng-hide="modalImageLoading" />
   <div class="spinner-border" ng-if="modalImageLoading"></div>
</div>

app.js

$scope.modalImageLoading = false;

$scope.fetchSinglegGiphy = function (giphy, index) {
   $scope.selectedIndex = index;
   $scope.selectedGiphy = giphy;
   $scope.modalImageLoading = true;
};

$scope.fetchSinglegGiphyModal = function (dir) {
   let selectedGiphy = null;
   if (dir === "prev") $scope.selectedIndex -= 1; // To load previous
   else if (dir === "next") $scope.selectedIndex += 1; // To load next

   selectedGiphy = $scope.giphyList[$scope.selectedIndex];
   if (selectedGiphy) {
      $scope.selectedGiphy = selectedGiphy;
      $scope.modalImageLoading = true;
   }
};

$scope.fetchSinglegGiphyModal作用于我们传入参数的条件,显示对应的Giphy数据。

我已经实现了一个自定义指令来显示图像元素并在下载图像时隐藏加载器。这是指令代码:

app.directive('imageOnLoad', function () {
   return {
      restrict: 'A',
      controller: 'giphyCtrl',
      link: function (scope, element, attrs) {
         element.bind('load', function () {
            scope.$apply(function () {
               scope.modalImageLoading = false;
            });
         });
      }
   }
});

这是修改后的 plunker code

希望对你有帮助!

【讨论】:

    【解决方案2】:

    当我单击任一控件时,GIF 文件保持不变

    检查giphy 是否等于您的预期:

    $scope.fetchSinglegGiphy = function(giphy, index) {
       $scope.selectedIndex = index;
       $scope.selectedGiphy = giphy;
       if ( giphy != $scope.giphyList[index] ) {
          $scope.selectedGiphy = $scope.giphyList[index];
       };
    };
    

    如果不是,请更新selectedGiphy

    【讨论】:

    • 我添加了一个 Plunker。请看一看。 :)
    【解决方案3】:

    您不仅在 ng-repeat 块之外使用 $index,而且在该块之外使用 giphy,它没有定义。

    我假设您在控制器中定义了 $scope.giphyList。所以你所要做的就是发送索引。

    $scope.selectedIndex = null;
    $scope.selectedGiphy = null;
    
    $scope.fetchSinglegGiphy = function(index) {
       $scope.selectedIndex = index;
       $scope.selectedGiphy = $scope.giphyList[index];
    }
    
    <div class="controls text-center">
        <a href="#" ng-click="fetchSinglegGiphy(selectedIndex-1)" class="left">
          <i class="fa fa-chevron-left"></i>
        </a>
        <a href="#" ng-click="fetchSinglegGiphy(selectedIndex+1)" class="right">
          <i class="fa fa-chevron-right"></i>
        </a>
    </div>
    

    我希望这会有所帮助, 干杯

    【讨论】:

    • 我已经更新了我的代码 - 添加了控制器的整个代码。请查看并更新您的答案。
    • 我认为我的回答仍然成立。您正在通过 ng-repeat 中的 gimphyList 进行迭代。您可以在其中使用 $index 调用 fetchSinglegGiphy。因此,当您单击缩略图时,它会将 $index 分配给 $scope.selectedIndex 并将 $scope.giphyList[index] 分配给 $scope.selectedGiphy。此时您的 selectedIndex 是所选缩略图的 $index。在 ng-repeat 之外,当您调用 fetchSinglegGiphy 转到下一个或上一个 gimphy 时,您需要发送 selectedIndex +/- 1。
    • 不幸的是,我已经实施了您的答案,不仅不起作用,而且破坏了我已经拥有的东西。 :(
    • 我创建了一支 CodePen Pen。它没有模态,但它可以完成您正在尝试做的事情。 link
    • 我添加了一个 Plunker。请看一看。谢谢!
    【解决方案4】:

    在将 giphy 移动到模态的地方,您还应该发送 $index(就像您实际所做的那样),因此在模态中您知道您的索引是谁,而不管 $index 是什么。

    <div class="controls text-center">
        <a href="#" ng-click="fetchSinglegGiphy(giphy, selectedIndex - 1)" class="left"><i class="fa fa-chevron-left"></i></a>
        <a href="#" ng-click="fetchSinglegGiphy(giphy, selectedIndex + 1)" class="right"><i class="fa fa-chevron-right"></i></a>
     </div>
    

    【讨论】:

    • div 中的这些控件带有 'ng-repeat' 指令?
    • 没有。从代码中可以看出它们在外面。
    • 我想获取网格中的下一个/上一个项目。我也试过fetchSinglegGiphy(giphy, $scope.index - 1)"
    • 我更改了回复。现在看。
    • 使用fetchSinglegGiphy(giphy, selectedIndex - 1)。结果是一样的。
    猜你喜欢
    • 1970-01-01
    • 2013-08-02
    • 2021-07-08
    • 2012-07-02
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    相关资源
    最近更新 更多