【问题标题】:Setting dynamic scope variables in AngularJs - scope.<some_string>在 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)获得这种行为,但是在赋值时如何做到呢?

【问题讨论】:

    标签: angularjs scope continuous-integration


    【解决方案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
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-21
          • 2015-08-08
          • 2017-07-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多