AngularJS: как избежать ошибки неназначения при предоставлении значений по умолчанию для отсутствующих атрибутов? - PullRequest
0 голосов
/ 07 сентября 2018

Это вопрос и ответ, потому что я немного боролся с проблемой, поэтому я хочу отслеживать ее и ее решение.
Надеясь, что это может помочь кому-то, и, возможно, другие люди могут предложить альтернативные решения.

Мой случай: мне пришлось работать над большим проектом AngularJS 1.4.6 (я назову его prj), написанным на TypeScript, определяющим количество директив (prj-ddd) с различными атрибутами (prj-aaa), некоторые из них логические.
Они реализовали эти логические атрибуты со связыванием строк: prjEnabled: "@" или prjRequired: "@".
Таким образом, они протестировали значения следующим образом: if ($scope.prjEnabled === "false") или в шаблонах: <div ng-show="prjRequired === 'true'"> (да, контроллер также не используется ...).
Эти атрибуты являются необязательными: очевидно, здесь prjEnabled по умолчанию "true" и prjRequired по умолчанию "false", среди прочего, потому что тесты false, когда эти значения undefined.

Это многословно, не элегантно (IMO), склонно к ошибкам (много необработанных строк, неявное значение по умолчанию) и не очень эффективно (хотя, вероятно, не ощутимо).

Итак, я начал заменять эти привязки выражением / двусторонней привязкой: prjEnabled: "=" и prjRequired: "=".
Таким образом, когда AngularJS видит <prj-component prj-enabled="false">, он прямо указывает логическое значение в области действия директивы.
Приятный штрих: с такими литеральными значениями он не создает привязки, поэтому производительность не падает.
Я должен справиться с отсутствующим атрибутом, поэтому я добавил в функцию link директив что-то вроде:

if (scope.prjEnabled === undefined) {
    scope.prjEnabled = true;
}

И использования становятся: if (!$scope.prjEnabled), или в шаблонах: <div ng-show="prjRequired">.

Пока все хорошо. Но у нас также есть явные привязки: <prj-component prj-enabled="{{someScopeValue}}"> или даже <prj-component prj-enabled="{{foo.canEdit && bar.valid}}">.
Поскольку у нас есть двусторонние привязки, я просто заменил их на: <prj-component prj-enabled="someScopeValue"> или <prj-component prj-enabled="foo.canEdit && bar.valid">.
Хорошо, если someScopeValue равен undefined, директива обнаружит это и предоставит значение по умолчанию, которое перейдет в родительскую область. Раздражает, но в большинстве случаев, вероятно, безвреден. Реальное значение обычно указывается позже (например, после сетевого запроса).
Но иногда в консоли появляется следующая ошибка:

https://code.angularjs.org/1.4.6/docs/error/$compile/nonassign?p0=foo.canEdit%20%26%26%20bar.valid&p1=prjComponent

Я следовал совету, приведенному на соответствующей странице, заменив привязки на "=?", но у меня все еще есть ошибка.

В идеале я бы заменил эти привязки на "<?", избегая первой проблемы (перезаписи значения в родительской области) и второй (без присваивания выражению).
Но для этого нужен AngularJS 1.5+, и я не могу обновить версию в текущем проекте.

Так как я могу решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Как вручную создать одностороннюю привязку со значением по умолчанию:

app.directive("myDirective", function() {
    return {
        scope: {
            //oneWay: "<?"
        },
        link: postLink
    };
    function postLink (scope, elem, attrs) {
        if (!attrs.oneWay) {
            scope.oneWay = defaultValue;
        } else {
            scope.$watch(attrs.oneWay, function(value) {
                scope.oneWay = value;
            });
        };
    }       
})

Для версий AngularJS (<1.5), которые не имеют односторонней привязки, это может быть реализовано с помощью наблюдателя. </p>

0 голосов
/ 07 сентября 2018

Это было сложно, и мне приходилось пробовать разные решения, пока я не увидел свет и не вспомнил, что с привязкой "=?" есть способ отличить отсутствующий атрибут от атрибута с атрибутом undefined.
Я переписал присвоение значения по умолчанию следующим образом:
if (!("prjEnabled" in scope)) { scope.prjEnabled = true; }
Если вы не знакомы с оператором in, он примерно эквивалентен scope.hasOwnProperty("prjEnabled"), но он также проверяет иерархию прототипа. Я использую его в основном потому, что он приятнее / сложнее, чем вызов функции ...

Я сделал заявление Plunkr (из официального приложения AngularJS), чтобы воспроизвести ошибку, посмотреть, когда она произошла, и изучить различные случаи: http://plnkr.co/edit/Z2AIag?p=preview

Это показывает, что при "=" привязке и назначении значения по умолчанию, если оно не определено, ошибка появляется, когда атрибут пуст (маловероятный случай) или когда AngularJS автоматически захватывает исключение (здесь wrong.scopeValue && wrong.unknown, где $scope.wrong нет существует, вызывая исключение ReferenceError) и предоставляет undefined в качестве значения.
С "=?" у нас все еще есть вторая проблема (регистр пустого значения атрибута не выдает).
Если мы тестируем с помощью метода "x" is scope, мы избавляемся от этого досадного случая, довольно распространенного, когда wrong является переменной, заполненной позже (обновление сети и т. Д.). Единственный случай, когда ошибка все еще может произойти, это если мы присвоим значение связанному атрибуту, и только в случае wrong.

...