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


97

我有一个从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),但是在分配值时如何实现呢?

Answers:


174

我发现的解决方案是使用$ 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

1
太漂亮了!但是(几乎总是有一个)我无法获得$ scope。$ apply()来传播我的数据。我可以在控制台日志中看到它,但是我的视图没有显示新添加的数据(我在显示$ scope的地方有一个页脚栏)-有什么想法吗?
william e schroeder 2014年

没有代码很难知道,但是我的第一个猜测是页脚不在同一个范围内。如果页脚位于带有ng-controller =“ YourController”的元素之外,则它将无法访问其变量。
Erik Honn 2014年

3
感谢你的回答。我想指出,assign还适用于复杂的对象,而不仅仅是原始类型。
Patrick Salami 2014年

1
为什么需要$ scope。$?
SINθ

我不太记得。我认为这是因为model.assign不会触发数据绑定,所以一旦完成所有需要做的事情,就需要手动应用。试用一下,看看是否可以删除它(在较新版本的Angular中可能也已更改,我认为这是一两个版本)。
Erik Honn 2014年

20

以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的情况下对其进行了测试。没有它就可以正常工作!


13
请注意,这与问题所在完全不同。该问题的目的是基于字符串创建一个动态作用域变量,其深度大于1。因此,要创建“ scope.life。意义”而不是“ scope.lifeMeaning”。使用$ scope [the_string]不会这样做。对于您的特定情况,请记住!undefined在javascrip中实际上是正确的,因此您实际上可以跳过整个if语句,而只需执行$ scope [the_string] =!$ scope [the_string];。虽然可能会使代码有些混乱,所以我不确定它是否确实是您想要的。
Erik Honn

@ErikHonn,实际上,$ scope [life。意义] = true对我有用!
杰西·弗朗西斯

1
它可以“工作”,但是除非在1.6中进行了更改,否则它不会执行与问题要求相同的操作。如果您执行$ scope [life。意义] = true,则该属性的名称将为“ life。意义”,这不是我们想要的。我们想要一个叫做生活的财产,它有一个叫做意义的孩子财产。
Erik Honn

13

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

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

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


5

如果可以使用Lodash,则可以使用_.set()在一行中完成所需的操作:

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

https://lodash.com/docs#set

因此,您的示例将仅仅是: _.set($scope, the_string, something);


4

只是为了添加给定的答案,以下对我有用:

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];
}

这与问题无关,请继续关注。
Erik Honn

抱歉,认为这可能有助于使用字符串创建动态变量。该线程帮助我编​​写了上面的代码,对我来说很好用。
Riaz

不用担心,想要提供答案是一个好的开始,只需确保首先阅读问题即可:)在这种情况下,它是将未知字符串“ abc”解析到对象{a:{b:{c:...} }}。但是处理重复项是一个常见的问题,因此很高兴您在线程中发现了一些问题。
埃里克·霍恩

哦,正如我在另一个答案中所指出的那样,如果仅假设值是true / false(或未定义),则可以跳过整个逻辑并执行$ scope [variable] ===!$ scope [variable],因为!undefined在javascript中为true。虽然如果您使用打字稿,我怀疑它会生您的气!
Erik Honn

3

请记住:这只是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

转到网络上搜索“角度$ apply”,您将找到有关$ apply函数的信息。而且,您应该更明智地使用这种方式(如果您没有$ apply阶段的约定)。

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

3
感谢您的回答,但问题不是为什么“简单版本”不起作用,这从一开始就是众所周知的。问题是替代方案是什么。恐怕您的两个建议都不会起作用,它们都需要您事先了解字符串的结构,而要点是要使其具有动态性(并能够处理任意字符串)。请参阅接受的答案以获取解决方案。
Erik Honn 2014年

1
同样,两个答案都无法真正解决问题。第一个失败了基本的先决条件,我们应该将它分配给$ scope.abc而不是$ scope ['abc'],第二个失败了,并且从字面上得出与“简单版本”完全相同的结果问题,只是使用了不需要的语法,但这也许是错字?:)
Erik Honn 2014年

0

如果您使用下面的Lodash库,则可以在角度范围内设置动态变量。

在角度范围内设置值。

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

从角度范围获取值。

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

-1

如果您要尝试执行我想像的操作,则只需将作用域视为常规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}}将返回一个数据主体名称数组,在我的示例中,将有$ scope中的{{jobs}},{{customers}},{{staff}}等范围属性。工作,$ scope.customers,$ scope.staff


4
感谢您的回答,但这不是一回事。它是关于从字符串创建$ scope.subject.name而不硬编码$ scope.subject。这与某些指令相关,如果您希望该指令可重用,则不应假定任何有关范围的内容。另外,angular.forEach()!不要让jQuery妨碍使用angular:P
Erik Honn
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.