AngularJsでの動的スコープ変数の設定-scope。<some_string>


97

routeParamまたはディレクティブ属性などから取得した文字列があり、これに基づいてスコープに変数を作成します。そう:

$scope.<the_string> = "something".

ただし、文字列に1つ以上のドットが含まれている場合は、分割して実際にスコープに「ドリルダウン」したいと思います。そう'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)、値を割り当てるときにどのように行うのですか?

回答:


174

私が見つけた解決策は$ parseを使うことです。

「角度式を関数に変換します。」

誰かがより良いものを持っている場合は、質問に新しい回答を追加してください!

次に例を示します。

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
これは美しいです!しかし(ほとんどの場合1つあります)、$ scope。$ apply()でデータを伝播できません。コンソールログで確認できますが、ビューに新しく追加されたデータが表示されません($ scopeを表示するフッターバーがあります)-何かアイデアはありますか?
william e schroeder 2014

コードを見ないとわからないが、フッターが同じスコープ内にないというのが私の最初の推測だろう。フッターがng-controller = "YourController"の要素の外側にある場合、そのフッターは変数にアクセスできません。
エリックホン

3
答えてくれてありがとう。assignは、プリミティブ型だけでなく、複雑なオブジェクトでも機能することを指摘しておきます。
Patrick Salami 2014

1
なぜ$ scope。$ applyが必要なのですか?
sinθと

実はよく覚えていません。これは、model.assignがデータバインディングをトリガーしないためだと思うので、必要なことをすべて実行したら、手動で適用する必要があります。試してみて、削除できるかどうかを確認してください(Angularの新しいバージョンでも変更されている可能性があります。これは1つまたは2つのバージョン前のバージョンだと思います)。
Erik Honn 2014年

20

エリックの答えを出発点として使用します。私に役立つ簡単な解決策を見つけました。

私の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.lifeMeaning」ではなく「scope.life.meaning」を作成します。$ scope [the_string]を使用してもそれはできません。また、特定のケースでは、!undefinedは実際にはjavascripでtrueであるため、ifステートメント全体を実際にスキップして$ scope [the_string] =!$ scope [the_string];を実行することもできます。ただし、コードを少し混乱させる可能性があるので、それが本当に必要なものかどうかはわかりません。
エリックホン2015

@ErikHonn、実際、$ scope [life.meaning] = trueは私のために働きました!
Jesse P Francis

1
それは「機能します」が、1.6で何かが変更されない限り、質問が要求するのと同じことを行いません。$ scope [life.meaning] = trueを実行すると、プロパティの名前は "life.meaning"になり、それは私たちが望むものではありません。意味と呼ばれる子プロパティを持つlifeというプロパティが必要です。
エリックホン

13

結果から動的角度変数を作成する

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

ps。$ parse属性をコントローラーの関数に渡すことを忘れないでください


5

Lodashを使用することに問題がなければ、_。set()を使用して1行で必要なことを実行できます。

_.set(object、path、value)オブジェクトのパスのプロパティ値を設定します。パスの一部が存在しない場合は作成されます。

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:...} }}。しかし、繰り返しアイテムを処理することは一般的な問題なので、スレッドで何か問題が見つかってうれしいです。
Erik Honn 2016

ああ、別の答えで述べたように、値がtrue / false(または未定義)であると想定されている場合は、ロジック全体をスキップして$ scope [variable] ===!$ scope [variable]を実行できます。 !undefinedはJavaScriptではtrueです。typescriptを使用している場合、私はそれがあなたに怒るのではないかと思います!
エリックホン

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

ウェブにアクセスして「angular $ apply」を検索すると、$ apply関数に関する情報が見つかります。そして、あなたはもっと賢明にこの方法を使うべきです(もしあなたが$ apply段階にまだならなければ)。

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

3
答えてくれてありがとうございますが、質問は「シンプルバージョン」が機能しない理由ではなく、最初からわかっていました。問題は、代替案が何であるかでした。私はあなたの2つの提案のどちらもうまくいかないと思います。どちらも事前に文字列の構造を知っている必要があり、ポイントは動的であること(そして任意の文字列を処理できること)です。解決策については、承認された回答を参照してください。
エリックホン2014年

1
また、どちらの回答も実際には問題を解決しません。1つ目は、$ scope ['abc']ではなく$ scope.abcに割り当てる必要があるという基本的な前提条件に失敗し、2つ目もこれに失敗して、文字通り「質問、不要な構文だけで、おそらくそれはタイプミスですか?:)
エリックホン

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をハードコーディングせずに、文字列から$ scope.subject.nameを作成することです。これは、ディレクティブを再利用可能にする場合は、スコープについて何も想定してはならない一部のディレクティブに関連します。また、angular.forEach()!jQueryにangular:Pを使用させないでください
Erik Honn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.