在 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>的主要内容,如果未能解决你的问题,请参考以下文章