在 AngularJs 中设置动态范围变量 - scope.<some_string>

Posted

技术标签:

【中文标题】在 AngularJs 中设置动态范围变量 - scope.<some_string>【英文标题】:Setting dynamic scope variables in AngularJs - scope.<some_string> 【发布时间】:2013-09-23 09:43:06 【问题描述】:

我有一个从routeParam 或指令属性或其他任何东西得到的字符串,我想在此基础上在范围上创建一个变量。所以:

$scope.<the_string> = "something".

但是,如果字符串包含一个或多个点,我想将其拆分并实际“向下钻取”到范围内。所以'foo.bar' 应该变成$scope.foo.bar。这意味着简单的版本将无法工作!

// This will not work as assigning variables like this will not "drill down"
// It will assign to a variables named the exact string, dots and all.
var the_string = 'life.meaning';
$scope[the_string] = 42;
console.log($scope.life.meaning);  // <-- Nope! This is undefined.
console.log($scope['life.meaning']);  // <-- It is in here instead!

在读取基于字符串的变量时,你可以通过$scope.$eval(the_string)获得这种行为,但是在赋值时如何做到呢?

【问题讨论】:

【参考方案1】:

我找到的解决方案是使用$parse。

“将 Angular 表达式转换为函数。”

如果有人有更好的答案,请为问题添加新答案!

示例如下:

var the_string = 'life.meaning';

// Get the model
var model = $parse(the_string);

// Assigns a value to it
model.assign($scope, 42);

// Apply it to the scope
// $scope.$apply(); <- According to comments, this is no longer needed

console.log($scope.life.meaning);  // logs 42

【讨论】:

所以这很漂亮!但是(几乎总是有一个)我无法让 $scope.$apply() 传播我的数据。我可以在控制台日志中看到它,但我的视图没有显示新添加的数据(我有一个显示 $scope 的页脚栏) - 有什么想法吗? 不看代码很难知道,但我的第一个猜测是页脚不在同一个范围内。如果页脚在 ng-controller="YourController" 的元素之外,那么它将无法访问其变量。 感谢您的回答。我想指出,assign 也适用于复杂对象,而不仅仅是原始类型。 为什么需要 $scope.$apply? 我不太记得了。我认为是因为 model.assign 不会触发数据绑定,所以你需要在完成所有需要做的事情后手动申请。试试看是否可以删除它(可能在较新版本的 Angular 中也发生了变化,我认为这是一两个版本)。【参考方案2】:

以 Erik 的回答为起点。我找到了一个对我有用的更简单的解决方案。

在我的 ng-click 功能中,我有:

var the_string = 'lifeMeaning';
if ($scope[the_string] === undefined) 
   //Valid in my application for first usage
   $scope[the_string] = true;
 else 
   $scope[the_string] = !$scope[the_string];

//$scope.$apply

我已经在使用和不使用 $scope.$apply 的情况下对其进行了测试。没有它也能正常工作!

【讨论】:

请注意,这与问题的内容完全不同。该问题的目标是基于字符串创建一个深度超过 1 的动态范围变量。所以要创建“scope.life.meaning”而不是“scope.lifeMeaning”。使用 $scope[the_string] 不会那样做。对于您的具体情况,请记住 !undefined 在 javascrip 中实际上是正确的,因此您实际上可以跳过整个 if 语句,只需执行 $scope[the_string] = !$scope[the_string];。虽然可能会混淆代码,所以我不确定它是否真的是你想要的。 @ErikHonn,实际上,$scope[life.meaning]=true 对我有用! 它“有效”,但除非在 1.6 中有所改变,否则它不会像问题所要求的那样做同样的事情。如果你这样做 $scope[life.meaning]=true 属性的名称将是“life.meaning”,这不是我们想要的。我们想要一个名为 life 的属性,它有一个名为 meaning 的子属性。【参考方案3】:

根据结果创建动态角度变量

angular.forEach(results, function (value, key)           
  if (key != null)                        
    $parse(key).assign($scope, value);                                
            
);

ps。不要忘记将 $parse 属性传递到控制器的函数中

【讨论】:

【参考方案4】:

如果你对使用 Lodash 没问题,你可以使用 _.set() 在一行中做你想做的事情:

_.set(object, path, value) 设置对象路径的属性值。如果路径的一部分不存在,则创建它。

https://lodash.com/docs#set

所以你的例子就是:_.set($scope, the_string, something);

【讨论】:

【参考方案5】:

只是为了添加到已经给出的答案中,以下内容对我有用:

html

<div id="div$index+1" data-ng-show="val$index">

$index 是循环索引。

javascript(其中value 是传递给函数的参数,它将是$index 的值,当前循环索引):

var variable = "val"+value;
if ($scope[variable] === undefined)

    $scope[variable] = true;
else 
    $scope[variable] = !$scope[variable];

【讨论】:

这与问题无关,请继续关注。 抱歉,我认为这可能有助于使用字符串创建动态变量。这个线程帮助我编​​写了上面的代码,这对我来说很好。 不用担心,想要提供答案是一个好的开始,请确保先阅读问题:) 在这种情况下,它是关于将未知字符串“abc”解析为对象 a: b : C: ...。但是处理重复项是一个常见问题,所以我很高兴你在线程中发现了一些有帮助的东西。 哦,正如我在另一个答案中指出的那样,如果值应该是真/假(或未定义),您可以跳过整个逻辑并执行 $scope[variable] === !$scope[variable],因为 !undefined 在 javascript 中为真。虽然如果你使用打字稿,我怀疑它会生你的气!【参考方案6】:

请记住:这只是一个 JavaScript 的东西,与 Angular JS 无关。所以不要对神奇的“$”符号感到困惑;)

主要问题是这是一个层次结构。

console.log($scope.life.meaning);  // <-- Nope! This is undefined.
=> a.b.c

这是未定义的,因为“$scope.life”不存在,但上面的术语想要解决“意义”。

解决方案应该是

var the_string = 'lifeMeaning';
$scope[the_string] = 42;
console.log($scope.lifeMeaning);
console.log($scope['lifeMeaning']);

或者多花点力气。

var the_string_level_one = 'life';
var the_string_level_two = the_string_level_one + '.meaning';
$scope[the_string_level_two ] = 42;
console.log($scope.life.meaning);
console.log($scope['the_string_level_two ']);

因为您可以使用

访问结构对象
var a = ;
a.b = "ab";
console.log(a.b === a['b']);

有几个很好的教程可以指导你玩转 JavaScript 的乐趣。

有一些东西

$scope.$apply();
do...somthing...bla...bla

去网上搜索'angular $apply',你会找到关于$apply 函数的信息。而且你应该更明智地使用这种方式(如果你还没有 $apply 阶段)。

$scope.$apply(function ()
    do...somthing...bla...bla
)

【讨论】:

感谢您的回答,但问题不是为什么“简单版本”不起作用,这是从一开始就知道的。问题是替代方案是什么。恐怕你的两个建议都行不通,它们都要求你事先知道字符串的结构,关键是它是动态的(并且能够处理任意字符串)。请参阅已接受的答案以获取解决方案。 另外,这两个答案都没有真正解决问题。第一个失败了基本的先决条件,我们应该分配给 $scope.abc 而不是 $scope['abc'],第二个也失败了,并导致与“简单版本”完全相同的东西这个问题,只是用了不需要的语法,但也许这是一个错字? :)【参考方案7】:

如果你使用 Lodash 库,下面是在角度范围内设置动态变量的方法。

在角度范围内设置值。

_.set($scope, the_string, 'life.meaning')

从角度范围获取值。

_.get($scope, 'life.meaning')

【讨论】:

【参考方案8】:

如果您尝试做我想象的您想做的事情,那么您只需将作用域视为常规 JS 对象。

这是我用于 JSON 数据数组的 API 成功响应...

function(data)

    $scope.subjects = [];

    $.each(data, function(i,subject)
        //Store array of data types
        $scope.subjects.push(subject.name);

        //Split data in to arrays
        $scope[subject.name] = subject.data;
    );

现在 subjects 将返回一组数据主体名称,在我的示例中,jobs、customers、staff 等将有一个范围属性来自$scope.jobs、$scope.customers、$scope.staff

【讨论】:

感谢您的回答,但这不是一回事。它是关于从字符串创建 $scope.subject.name 而不对 $scope.subject 进行硬编码。这在某些指令中是相关的,如果您希望指令可重用,您不应该假设任何关于范围的内容。此外,angular.forEach()!不要让 jQuery 妨碍使用 angular :P

以上是关于在 AngularJs 中设置动态范围变量 - scope.<some_string>的主要内容,如果未能解决你的问题,请参考以下文章

如何在angularjs中设置范围滑块的时间?

在 AngularJS 中设置应用程序范围的 HTTP 标头

AngularJS:如何在模板中设置变量?

如何在不使用 %s 的情况下安全、动态地在查询中设置列名?

AngularJS指令隔离范围和父范围

如何在 BigQuery 中设置动态会计日期范围?