如何在子作用域的指令中设置Angular控制器对象属性值

18

我在ng-repeater内部有一个指令,应该设置作用域属性。 请查看这里的fiddle: http://jsfiddle.net/paos/CSbRB/

问题在于作用域属性被赋予了像这样的属性值:

<button ng-update1="inputdata.title">click me</button>
该指令应该将作用域属性inputdata.title设置为某个字符串。但是这并没有起作用。
app.directive('ngUpdate1', function() {
    return function(scope, element, attrs) {
        element.bind('click', function() {
            scope.$apply(function() {
                scope[ attrs.ngUpdate1 ] = "Button 1";
            });
        });
    };
});

然而,直接赋值也可以:

scope["inputdata"]["title"] = "Button 1";

请问如何从指令中使用点符号在名称中设置作用域属性?

附注:此示例中使用重复器是因为它使指令成为子作用域。当它们在子作用域中时,无法编写原始数据类型的作用域属性。这就是为什么我需要一个名称中带有“.”的对象属性。请参见此处的详细说明:AngularJS中作用域的原型/原型继承的细微差别是什么?

谢谢


一个不太优雅的解决方案是使用 $apply 的字符串形式,例如:scope.$apply( attrs.ngUpdate1 + '=' + '"Button 1"' ); - Josh David Miller
@Josh,如果你没有看到我的回答,优雅的解决方案是使用$parse - Mark Rajcok
2个回答

37

$parse会解决你的问题。

<button ng-update1="inputdata.title">
app.directive('ngUpdate1', function($parse) {
    return function(scope, element, attrs) {
        var model = $parse(attrs.ngUpdate1);
        console.log(model(scope));  // logs "test"
        element.bind('click', function() {
           model.assign(scope, "Button 1");
           scope.$apply();
        });
    };
});

Fiddle

当指令没有使用隔离作用域并且您使用属性指定了作用域属性,并且您想修改该值,则使用$parse

如果您不需要修改该值,则可以使用$eval代替:

console.log(scope.$eval(attrs.ngUpdate1));

你能否使用ng-model作为HTML属性来完成相同的操作,假设你的HTML元素是一个指令,并且你已经在链接函数中编写了你在这里展示的代码? - sonicblis
@sonicblis,我建议您发布一个新的问题,并提供一个fiddle,因为您询问的是非常不同的情况。答案也将取决于指令使用的作用域类型。这可能会有所帮助:https://dev59.com/Z2ct5IYBdhLWcg3wsPZ5 - Mark Rajcok
@MarkRajcok,感谢您的帮助,但我已经解决了。这个fiddle展示了我所询问的内容。 - sonicblis

2

不确定整体目标是什么,但一种方法是创建两个属性,一个用于目标对象,另一个用于该对象的属性:

<button ng-update1  obj="inputdata" prop="title">

app.directive('ngUpdate1', function() {
    return function(scope, element, attrs) {
        element.bind('click', function() {
            scope.$apply(function() {                
                scope[ attrs.obj ][attrs.prop] = "Button 1";               

            });
        });
    };
});

示例:http://jsfiddle.net/CSbRB/9/

或者您可以使用现有的格式,通过split()函数拆分您当前ng-update1属性的值,并将结果数组用于对象和属性的表示。

 element.bind('click', function() {
           var target=attrs.ngUpdate1.split('.');
            scope.$apply(function() {                
                scope[ target[0] ][target[1]] = "Button 1";               

            });
        });

两种方法的示例演示:http://jsfiddle.net/CSbRB/10/

另一种方法是在指令中创建一个隔离作用域,并可以传入对inputdata对象的引用,并从属性中提取属性名称(与第二个版本相同的标记):

app.directive('ngUpdate3', function () {
    return {
        scope: {
           targetObject: '=obj'
        },
        link: function (scope, element, attrs) {
            element.bind('click', function () {  
               scope.$apply(function () {
                    scope.targetObject[attrs.prop]='Button 3';

                });
            });
        }
    }
});

http://jsfiddle.net/CSbRB/11/


不要使用两个属性或 split(),而是使用 $parse(请参见我的答案)。此外,如果需要隔离作用域,您可以直接绑定到对象属性:<button ng-update3 model="inputdata.title" ...>,然后在指令中:scope: { model: '=' }Fiddle - Mark Rajcok
@MarkRajcok 谢谢。之前我试图绑定到隔离作用域中的属性,但不确定为什么它不起作用。$parse 的文档太糟糕了……你的评论很有帮助。似乎应该有更直观的方法,而不需要使用 $parse 然后 assign - charlietfl
我在你的fiddle中绑定到一个隔离作用域的属性时遇到了问题。我认为问题在于你的fiddle中使用了较旧版本的Angular(1.0.0)。 - Mark Rajcok
三种不同的方法让我的思维开阔了。非常感谢您提供有用的解释。 - Thomas.Benz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接