为啥我不能像这样覆盖变量的值?

Posted

技术标签:

【中文标题】为啥我不能像这样覆盖变量的值?【英文标题】:Why can't I overwrite the value of a variable like this?为什么我不能像这样覆盖变量的值? 【发布时间】:2015-09-09 20:27:53 【问题描述】:

我试图弄清楚为什么我无法覆盖通过隔离范围 (@) 传递给 angularJS 指令的值。我尝试用以下内容覆盖vm.index 的值:

vm.index = parseInt(vm.index, 10)

但是,由于某种原因,它不起作用。

如果我将其更改为:

vm.newIndex = parseInt(vm.index, 10)

它有效。此外,在 $scope 上分配值也可以。

为什么第一种方法不起作用?

我创建了这个example plunker 以供参考。

【问题讨论】:

你说它“不起作用”到底是什么意思? 对不起,我的意思不是 vm.index 不会从字符串转换为数字,这会在执行 vm.index + 1 之类的操作时导致字符串连接。 @brso05,我知道。但是,范围不是问题,因为您可以通过将vm.index = ... 更改为vm.newIndex = ... 并更新模板以使用vm.newIndex + 1 来验证自己。 @RaphaelRafatpanah 你能看看我更新的答案吗..这会让你更清楚为什么vm.index 不能通过直接从控制器直接parseInt 工作 插件链接已失效。 【参考方案1】:

正如您在此处使用的@,它需要来自带有 插值指令的属性的值。似乎指令首先被加载,然后vm.index 值被评估。因此,在当前的摘要周期中没有发生变化。如果您希望反映这些内容,您需要使用 $timeout 以更安全的方式运行摘要循环。

$timeout(function()
  vm.index = parseInt(vm.index, 10)
)

最重要的是确保将值转换为十进制值。添加将发生在指令 html <h2>Item vm.index + 1 </h2>

Working Demo

这背后的可能原因

根据@dsfq 和我的讨论,我们通过了角度$compile API,发现它们是一种方法调用initializeDirectiveBindings,只有当我们在具有隔离范围的指令中使用controllerAs 时才会调用它。在此函数中,有各种绑定 @=& 的 switch case,因此当您使用 @ 时,这意味着调用 switch case 代码之后的一种方式绑定。

代码

case '@':
    if (!optional && !hasOwnProperty.call(attrs, attrName)) 
        destination[scopeName] = attrs[attrName] = void 0;
    
    attrs.$observe(attrName, function(value) 
        if (isString(value)) 
            destination[scopeName] = value;
        
    );
    attrs.$$observers[attrName].$$scope = scope;
    if (isString(attrs[attrName])) 
        // If the attribute has been provided then we trigger an interpolation to ensure
        // the value is there for use in the link fn
        destination[scopeName] = $interpolate(attrs[attrName])(scope);
    
    break;

在上面的代码中,您可以清楚地看到他们在那里放置了attrs.$observe,这是一种观察者,通常在值与插值时使用,就像在我们的例子中它是相同的index,这意味着这个@987654340 @ 在摘要循环运行时被评估,这就是为什么您需要将 $timeout 设置为 index 值作为 decimal

@dsfq 回答之所以有效,是因为他使用= 提供了两种方式绑定,即代码不会让观察者直接从隔离范围here is the code 中获取值。因此,如果没有摘要循环,该值将得到更新。

【讨论】:

这是解决问题的正确方法。发生的情况是控制器在 指令范围配置扩展之前被初始化。所以控制器首先运行,然后 scope => index 从属性值创建控制器的 this.index ,这是一个字符串。它会覆盖您在控制器中设置的任何内容。【参考方案2】:

显然它与作用域index 值的单向绑定有关。所以Angular不会更新scope.index(或者this.indexbindToController: true)因为范围配置为

scope: 
    index: '@'
,

如果您将其更改为双向绑定,例如:

scope: 
    index: '='
,

它会起作用的:

<some-directive index="$index"></some-directive>

演示: http://plnkr.co/edit/kq16cpk7gyw8IE7HiaQL?p=preview

UPD。 @pankajparkar 提出了一个很好的观点,即在下一个摘要中更新值解决了这个问题。这种解决问题的方法比我在这个答案中所做的更接近。

【讨论】:

对不起。但我认为你误读了这个问题。为什么范围的事情有效而 vm.index 事情不工作,我的意思是在指令 html 上添加 .. 是的,看起来你是对的,但不清楚为什么在这种情况下需要下一个摘要。 这可能是因为@ 或者我可以说插值指令..指令首先被初始化&在解析器评估后填充值 是的,它肯定与@ 有关,但在这种情况下我不确定整个机器。但是你提出了一个很好的超时问题。 感谢您的赞赏..您的解决方案也很酷..但没有解释 OP 的问题答案..

以上是关于为啥我不能像这样覆盖变量的值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用类变量的这段代码不能像在 Java 中那样工作? [复制]

为啥我不能更改 Timer.scheduledTimer 函数中变量的值?

为啥我不能像这样实例化一个对象? [复制]

为啥我不能像传递其他变量一样将函数从 Express.js 传递给 EJS?

为啥我不能使用像 $(document) 这样的 iframe 文档

为啥我不能在 div 中覆盖 img?