Angular Directive - создать новую привязку для двух сторон и передать по значению

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

<my-directive att>                //Evaluates to true
<my-directive att="true">        
<my-directive att="false">
<my-directive att="51">
<my-directive att="51.234">
<my-directive att="'john smith'">  

или можно использовать двустороннюю привязку к переменной в такой области.

<my-directive att="SomeVariableOnControllerScope"> 

Теперь это не будет работать со стандартной двухсторонней привязкой "=". Я пробовал разные попытки, но всякий раз, когда вы пытаетесь что-то изменить в своей директиве, он пытается записать это обратно в переменную, и если это не правильная переменная, вы получаете стандартную ошибку «неназначаемая».

Но кто-то намекнул на то, что можно было бы создать новый тип переплета. Теоретически этот новый тип привязки может смотреть на переданное значение, чтобы увидеть, было ли оно логическим, целым числом, числом с плавающей запятой или строкой в ​​одинарных кавычках. Если бы это было так, он мог бы использовать это и «отключить» двустороннюю привязку, чтобы ничего не было записано обратно. Если значение не является ни одним из переданных, то оно будет работать точно так же, как =, и установит двустороннюю привязку.

Я понятия не имею, как это сделать, но, возможно, смогу решить это, если подтолкнуть в правильном направлении. Ценность в том, что нам часто нужно выводить HTML с сервера (по причинам SEO), который устанавливает значение и часто не нужно связываться с чем-то в контроллере. Однако иногда требуется двусторонняя привязка.

Итак, в основном то, что я ищу, - это гибридная привязка @ и =, которая разумно знает, передается ли значение или имя переменной.

Любые идеи?


person jonhobbs    schedule 20.11.2015    source источник
comment
Вместо этого вы можете использовать @ operator и передать дополнительный атрибут для типа данных. Затем вы можете привести значение к желаемому типу данных внутри директивы.   -  person Vivek    schedule 20.11.2015


Ответы (1)


1/ Служба $parse может анализировать значение и определять, является ли оно константой или нет.

https://docs.angularjs.org/api/ng/service/$parse

2/Это код, используемый в изолированных областях для привязки двойных областей:

        var dataBind = function(parentScopeName, scopeName, childScope, parentScope) {
        if(parentScope == null) {
            parentScope = childScope.$parent;
        }
        var parentGet = $parse(parentScopeName);
        var compare = parentGet.literal ? angular.equals : function(a,b) { return a === b; };
        var lastValue;

        var parentSet = parentGet.assign || function() {
            // reset the change, or we will throw this exception on every $digest
            lastValue = childScope[scopeName] = parentGet(parentScope);
            throw "didnt understand this exception";
        };
        lastValue = childScope[scopeName] = parentGet(parentScope);
        return childScope.$watch(function parentValueWatch() {
            var parentValue = parentGet(parentScope);
            if (!compare(parentValue, childScope[scopeName])) {
                // we are out of sync and need to copy
                if (!compare(parentValue, lastValue)) {
                    // parent changed and it has precedence
                    childScope[scopeName] = parentValue;
                } else {
                    // if the parent can be assigned then do so
                    parentSet(parentScope, parentValue = childScope[scopeName]);
                }
            }
            return (lastValue = parentValue);
        }, null, parentGet.literal);
    }

Таким образом, вы можете делать то, что хотите, комбинируя этот метод и службу $parse (хотя вы не сможете использовать изолированную область видимости '=' или '@'):

var parsed = $parse($attrs.myAttribute);
if(parsed.constant) {
     $scope.whereIWantMyConstantInChildScope = parsed();
} else {
     dataBind($attrs.myAttribute, "whereIWantMyConstantInChildScope", $scope); // 4rth param is optional, will fallback to parent scope.
}

Это техническое решение.

Тем не менее, я думаю, что наилучшей практикой было бы обрабатывать эти два случая (константа и привязка) с двумя разными атрибутами (поскольку в основном существуют очень разные потребности, и желание объединить два поведения очень похоже на разработку, основанную на лени), и if/else в вашей ссылке на директиву изолированной области. Это позволит избежать всего этого бесполезного перегрева кода...

person Pierre Gayvallet    schedule 20.11.2015
comment
Я частично согласен с последним утверждением, хотя оно вызвано не ленью, а желанием предоставить пользователям моего фреймворка гибкость, позволяющую обойтись без двух версий каждого атрибута. например директива карты с атрибутами draggable=true, latitude=51,3489 longitude=0,1246 также потребует следующих атрибутов: draggable-model=myScope.draggable latitude-model=myScope.latitude и т. д. Это не кажется очень СУХИМ, когда у вас много атрибуты, установка двойных привязок, двойных часов и т. д. Это кажется грязным, но тогда эта новая гибридная привязка кажется хакерской. - person jonhobbs; 20.11.2015
comment
Не будет удваивать часы, если они автоматизированы с помощью базовой логики (пример my-attr -> watch, my-attr-static -> константа) и обработаны при связывании (это не более чем то, что делает angular в изолированной директивной привязке, и это легко факторизовать в утилиту) Но это означает отказ от всех использований изолированных областей (но это не проблема, ИМХО, отбрасывание использования изолированных областей — это первый необходимый шаг к пониманию того, как на самом деле работает angular и как вы можете оптимизировать материал...) - person Pierre Gayvallet; 20.11.2015