Как AngularJS знает, что нужно проверять / запускать условие ‘isToggled’ в этом рабочем примере?

#angularjs

#angularjs

Вопрос:

Я изучаю некоторые основы angularjs, и я случайно наткнулся на шаблон, который работает, но я не уверен, почему. Также не уверен, делаю ли я это в духе «angular best practices». Этот пример значительно упрощен по сравнению с тем, над чем я действительно работаю, но общая концепция та же: настройка видимости дочерних элементов на основе переключения на родительском

Моему наивному, наивному я кажется, что он должен каким-то образом наблюдать за функциями, которые используют toggledGroups массив, а затем ???. Условие ng-show действительно работает, я просто не совсем понимаю, почему ng-show="isToggled(group)" оно переоценивается, поскольку массив, который я изменяю, не включен $scope .

  • Все ли функции, которые существуют в $scope , переоцениваются при каждом $digest ? Если это так, мне кажется, что это может создать узкое место для ng-repeats больших наборов данных.

  • Как я упоминал выше, является ли это приемлемым шаблоном или есть лучший / «более угловой» способ, которым я должен думать об этом взаимодействии?

JS:

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

app.service('TransportationService', function(){
    var groups = [{
        group: "planes",
        items: ["Airbus A300", "Extra 300S", "Stearman"]
    },  {
        group: "trains",
        items: ["Flying Scotsman", "The Rocket", "Silver Streak"]
    }, {
        group: "automobiles",
        items: ["Veyron", "Vanquish", "FF", "Continental GT"]
    }];

    return {
        groups: groups
    }
});

app.controller('TransportationController', ['$scope', 'TransportationService', function($scope, ts){
    var toggledGroups = [];

    function isToggled(group) {
        return toggledGroups.indexOf(group) > -1;
    }

    function toggleGroup(group) {
        var index = toggledGroups.indexOf(group);
        if (index > -1) {
          toggledGroups.splice(index, 1);
        } else {
          toggledGroups.push(group);
        }
    }

    $scope.groups = ts.groups;
    $scope.isToggled = isToggled;
    $scope.toggleGroup = toggleGroup;
}]);
  

HTML:

 <div ng-app="demo" ng-controller="TransportationController">
    <div ng-repeat="group in groups">
        <h3>{{group.group}}</h3>
        <button ng-click="toggleGroup(group)">Toggle</button>
        <ul ng-show="isToggled(group)">
            <li ng-repeat="item in group.items">{{item}}</li>
        </ul>
    </div>
</div>
  

Скрипка: http://jsfiddle.net/wpHZg/1 /

Комментарии:

1. К какому условному оператору вы имеете в виду, который повторно вычисляется?

2. the isToggled(group) . Извините, я плохо сформулировал это

3. Я поставил какую-то консоль. журнал внутри функции isToggled, заметил, что каждый раз он вызывает его 6 раз странно…

4. Вы правы. Все свойства в $scope просматриваются и оцениваются. isToggled (group) будет повторно оцениваться при нажатии кнопки, поскольку он пытается повторно отобразить представление. Есть несколько вещей, которые вы можете сделать, чтобы сделать его немного лучше, хотя и не связанных с вашим вопросом. Смотрите скрипку здесь — jsfiddle.net/jain208/wpHZg/6 . Во-первых, я заменил ng-show на ng-if , что немного более эффективно, чем ng-show, плюс элемент не занимает места в DOM. Во-вторых, я упростил ваш метод ToggleGroup, добавив свойство isVisible для group .

5. @mcpDESIGNS: я тоже это заметил. Как в моей демонстрации, так и в моем реальном приложении isToggled функция вызывается дважды для каждого рендеринга (34 элемента, 68 вызовов на рендеринг). Происходит с обоими ng-if и ng-show

Ответ №1:

Ваши предположения верны. Каждый раз, когда запускается цикл дайджеста, он выполняет эту функцию. Вы также правы в том, что это дороже. Насколько дороже? Зависит от размера вашего набора данных. Исходя из логики, которую вы показываете, я не могу представить, что это будет слишком сложно для процессора, но вы должны учитывать тот факт, что это будет накладываться на всю другую логику вашего приложения. Насколько я понимаю, вы могли бы предпринять 2 действия, чтобы уменьшить нагрузку на клиентский процессор.

1) легко: добавьте переключаемое свойство в свои группы:

 $scope.toggleGroup = function(group) {
  group.toggled = !group.toggled
};

<ul ng-if="group.toggled"></ul>
  

2) Более сложный: допускает некоторую сухость, создайте директиву! : D

 app.directive('toggler', function() {
   return {
     restrict: 'A',
     link: function(scope, elem) {
       elem.find('.button-toggler').on('click', function() {
         elem.find('.togglee').toggle();
       });
     }
   };
});

<div toggler="">
  <button class="button-toggler">Toggle Me Hard!</button>
  <ul class="togglee" style="display:none"></ul>
</div>
  

Второй вариант позволяет вам легко переносить вашу директиву в другие части вашего кода. Он также не запустит цикл дайджеста, поскольку он полностью основан на jQuery (что в данном случае хорошо, потому что вы не меняете какие-либо данные области при нажатии). В любом случае у вас будет более чистое приложение.

Комментарии:

1. Также не забудьте использовать track by в вашем ng-repeat s. Это уменьшает количество повторных отображений, которые приложение выполняет в DOM.

2. Кроме того, по возможности используйте ng-if вместо ng-show .

3. Это правда, @AbhishekJain

4. track by и ng-if может внести огромные улучшения, согласованные!

5. @Mike: мне нужно будет посмотреть track by и ng-if . Я не знал об этом. Спасибо!