Angular ng-show不会连续检查条件

Angular ng-show does not check the condition continuously?

本文关键字:检查 条件 连续 ng-show Angular      更新时间:2023-09-26

我有一个ng-repeat指令,我显示所有的对象(想法)。如果一个想法描述(字符串)比x长,我想只显示前x个字符和一个"显示全部"链接。用户可以点击这个链接,全文就会显示出来。但是一次只能显示一个想法和它的全文。

我现在有这个:

div(ng-show = "idea.description.length > maxIdeaDescLength && openLongIdea != idea._id")
  i {{idea.description.substring(0, maxIdeaDescLength) }} ...
  a(href='', ng-click='openLongIdea = idea._id') show all
div(ng-show = "idea.description.length <= maxIdeaDescLength || openLongIdea == idea._id")
  i {{idea.description}}

这是我的控制器的一部分:

$scope.openLongIdea = 0;

所以当我点击show all链接时,ideaID将被保存到变量openLongIdea。由于我的ng-show条件,我希望只在idea-ID与openlongiidea - id匹配时显示整个描述。但我仍然看到不止一个想法,每次都有很长的描述。

当想法第一次出现时,我的逻辑工作了。当我点击一个显示所有链接,较长的文本将被显示。但是当我点击另一个idea的see all链接时,它也会在旧idea旁边作为一个整体显示,尽管我用新的idea - id覆盖了openLongIdea中的值。

这里有什么问题?

正如在注释中所指出的,这看起来像是绑定到原语的问题。在JavaScript中,原语(布尔值、数字、字符串)是不可变的,所以当你改变一个原语时,比如你的数字maxIdeaDescLength,前一个实例将被丢弃,并使用一个新的。这会破坏Angular的双向绑定,并且maxIdeaDescLength的任何其他用法都不会被更新为新值。

您可以通过将openLongIdea设置为$scope(例如$scope.data.openLongIdea)上对象的属性来解决此问题。在这种情况下,即使maxIdeaDescLength发生变化,$scope也有对data的引用,因此可以访问maxIdeaDescLength的更新值。

但是,请考虑切换到controllerAs视图语法。来自John Papa的风格指南,以及其他参数:

它提倡在视图中使用绑定到"带点"的对象(例如;Customer.name(而不是name),它更具有上下文关系,更容易读取,并避免可能发生的任何参考问题"打点"。

更新控制器:

var app = angular.module("app", []);
app.controller('ctrl', function () {
  var vm = this;
  vm.maxIdeaDescLength = 10;
  vm.ideas = [
    {_id : 0, description :'abcd efgh ijkl'},
    {_id : 1, description :'qwer tyui opzx'}
  ];
});

示例视图:

<div ng-app="app" ng-controller="ctrl as vm">
  <div ng-repeat="idea in vm.ideas">
    <div ng-show = "idea.description.length > vm.maxIdeaDescLength && vm.openLongIdea !== idea._id">
      {{idea.description.substring(0, vm.maxIdeaDescLength) }} 
      <a href='' ng-click='vm.openLongIdea = idea._id'> show all </a>
    </div>
    <div ng-show = "idea.description.length <= vm.maxIdeaDescLength || vm.openLongIdea === idea._id">
      {{idea.description}}
    </div>
  </div>
</div>

JsFiddle

我将为此创建一个自定义过滤器指令,因为它将更具可读性。另一个答案中推荐的controllerAs非常好,我在演示中遗漏了这一点。

请看看下面的演示或在这个小提琴。

在演示中可以通过单击段落来折叠/展开。

指令可以在一个点上得到改进,如果你切换每个单一的想法,你可能需要点击show/hide all按钮两次,如果当前的globalDisplay不匹配。

关于"。rule",请看看这个SO问题。

angular.module('demoApp', [])
	.constant('appConst', {
    	maxIdeaDescLength: 50,
    	expandedDefault: false
	})
	.filter('descLimit', descLimitFilter)
	.controller('MainController', MainController);
function descLimitFilter($filter) {
	return function(input, len, expanded, ellipsesChars) {
        var ellipses = ellipsesChars || '...';
    	return expanded? input : $filter('limitTo')(input, len) + ellipses;
    }
}
function MainController($scope, $http, appConst) {
    $scope.maxIdeaDescLength = appConst.maxIdeaDescLength;
    $scope.toggle = toggle;
    $scope.toggleAll = toggleAll;
    
    var globalDisplay = appConst.expandedDefault; // hide all by default;
    
    activate();
    
	function activate() {
        $http.get('https://demo5147591.mockable.io/ideas')
            .then(function(response) {
                $scope.ideas = response.data;
                //console.log(response.data);
            	setExpandedAll($scope.ideas, globalDisplay);
        });
    }
    
    function toggle(item) {
    	item.expanded = !item.expanded;
    }
    
    function toggleAll(items) {
        globalDisplay = !globalDisplay;
    	setExpandedAll(items, globalDisplay);
    }
    
    function setExpandedAll(items, state) {
    	angular.forEach(items, function(item) {
        	item.expanded = state;
        });
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="MainController">
    <button ng-click="toggleAll(ideas)">show/hide descriptions</button>
    <div>
        <div ng-repeat="idea in ideas">
            <h2>{{idea.title}}</h2>
            <p ng-click="toggle(idea)">{{idea.description | descLimit: maxIdeaDescLength : idea.expanded}}</p>
        </div>
    </div>
</div>