Angular 指令 - 为两种方式创建新绑定 "pass by value"

Angular Directive - create new binding for two way and "pass by value"

这是对上一个问题(和类似问题)的扩展,在该问题中我询问是否可以在指令上设置一个属性以允许像这样传递值。

<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"> 

现在,这不适用于标准的“=”双向绑定。我尝试了各种尝试,但每当您尝试更改指令中的某些内容时,它都会尝试将其写回变量,如果它不是正确的变量,您会得到标准的 "non assignable" 错误。

但是,有人暗示可以创建一种新型绑定。理论上,这种新型绑定可以查看传入的值,看它是布尔值、整数、浮点数还是单引号中的字符串。如果是的话,它可以使用那个和 "switch off" 双向绑定,这样就不会回写任何内容。如果值是那些传递的 none 那么它将完全按照 = 做并设置双向绑定。

我不知道该怎么做,但如果在正确的方向上推动,也许能够解决这个问题。这样做的价值在于我们经常需要从服务器输出 HTML(出于 SEO 的原因),它设置了一个值并且通常不需要与控制器中的某些东西绑定。但是有时需要 2 种方式绑定。

所以,基本上我正在寻找的是混合 @ 和 = 绑定,它智能地知道传递的是值还是变量名。

有什么想法吗?

1/ $parse 服务能够解析一个值并判断它是否是常量

https://docs.angularjs.org/api/ng/service/$解析

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.
}

这是技术方案。

但是,我认为最好的做法是用两个不同的属性来处理这两种情况(常量与绑定),(因为基本上有非常不同的需求,想要合并这两种行为看起来很像懒惰- driven-development), 和一个 if/else 在你的 isolated-scope 指令链接中。这将避免所有这些无用的代码过热...