Angular Directive - 为双向创建新绑定并“按值传递”

时间:2015-11-20 11:24:57

标签: javascript angularjs 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原因),它设置一个值,通常不需要与控制器中的某些东西绑定。但有时需要双向绑定。

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

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

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

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

这是技术解决方案。

但是,我认为最好的做法是使用两个不同的属性处理这两种情况(常量与绑定)(因为基本上有非常不同的需求并且想要合并这两种行为看起来非常像懒惰驱动 - 开发),以及你的隔离范围指令链接中的if / else。这样可以避免所有这些无用的代码过热...