Menyetel variabel cakupan dinamis di AngularJs - cakupan. <some_string>


97

Saya memiliki string yang saya dapatkan dari routeParamatau atribut direktif atau apa pun, dan saya ingin membuat variabel pada ruang lingkup berdasarkan ini. Begitu:

$scope.<the_string> = "something".

Namun, jika string berisi satu atau beberapa titik, saya ingin membaginya dan benar-benar "menelusuri" ke dalam cakupan. Jadi 'foo.bar'seharusnya menjadi $scope.foo.bar. Artinya, versi sederhana tidak akan berfungsi!

// 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!

Saat membaca variabel berdasarkan string, Anda bisa mendapatkan perilaku ini dengan melakukan $scope.$eval(the_string), tetapi bagaimana melakukannya saat menetapkan nilai?

Jawaban:


174

Solusi yang saya temukan adalah dengan menggunakan $ parse .

"Mengubah ekspresi Angular menjadi sebuah fungsi."

Jika ada yang punya jawaban yang lebih baik tolong tambahkan jawaban baru untuk pertanyaan itu!

Berikut contohnya:

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
Jadi ini indah! Tetapi (dan hampir selalu ada satu) saya tidak bisa mendapatkan $ scope. $ Apply () untuk menyebarkan data saya. Saya dapat melihatnya di log konsol, tetapi tampilan saya tidak menunjukkan data yang baru ditambahkan (Saya memiliki bilah footer tempat saya menampilkan $ scope) - Ada ide?
william e schroeder

Sulit untuk mengetahui tanpa melihat kode, tetapi tebakan pertama saya adalah bahwa footer tidak berada dalam cakupan yang sama. Jika footer berada di luar elemen dengan ng-controller = "YourController" maka ia tidak akan memiliki akses ke variabelnya.
Erik Honn

3
Terima kasih atas jawabannya. Saya ingin menunjukkan bahwa assign juga berfungsi dengan objek kompleks, bukan hanya tipe primitif.
Patrick Salami

1
Mengapa $ scope. $ Apply diperlukan?
sinθ

Sebenarnya aku tidak terlalu ingat. Saya pikir itu karena model.assign tidak memicu pengikatan data, jadi Anda perlu menerapkan secara manual setelah Anda melakukan semua yang perlu Anda lakukan. Cobalah dan lihat apakah mungkin untuk menghapusnya atau tidak (mungkin telah berubah di versi Angular juga, saya pikir ini adalah satu atau dua versi sebelumnya).
Erik Honn

20

Menggunakan jawaban Erik, sebagai titik awal. Saya menemukan solusi yang lebih sederhana yang berhasil untuk saya.

Dalam fungsi ng-click saya, saya memiliki:

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

Saya telah mengujinya dengan dan tanpa $ scope. $ Apply. Bekerja dengan benar tanpanya!


13
Perhatikan bahwa ini adalah sesuatu yang sama sekali berbeda dari pertanyaannya. Tujuan dari pertanyaan ini adalah untuk membuat variabel cakupan dinamis dengan lebih dari 1 kedalaman berdasarkan string. Jadi untuk membuat "scope.life.meaning" dan bukan "scope.lifeMeaning". Menggunakan $ scope [the_string] tidak akan melakukannya. Dan untuk kasus spesifik Anda, ingatlah bahwa! Undefined sebenarnya benar dalam javascrip, jadi Anda sebenarnya dapat melewati seluruh pernyataan if dan hanya melakukan $ scope [the_string] =! $ Scope [the_string] ;. Mungkin sedikit mengacaukan kode, jadi saya tidak yakin apakah itu benar-benar sesuatu yang Anda inginkan.
Erik Honn

@ErikHonn, sebenarnya, $ scope [life.meaning] = true berhasil untuk saya!
Jesse P Francis

1
Ini "berfungsi", tetapi kecuali ada sesuatu yang diubah di 1.6, itu tidak melakukan hal yang sama seperti yang diminta pertanyaan. Jika Anda melakukan $ scope [life.meaning] = true, nama propertinya adalah "life.meaning", dan bukan itu yang kami inginkan. Kami menginginkan properti bernama kehidupan yang memiliki properti anak yang disebut makna.
Erik Honn

13

Buat variabel sudut dinamis dari hasil

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

ps. jangan lupa untuk memasukkan atribut $ parse ke dalam fungsi pengontrol Anda


5

Jika Anda tidak masalah menggunakan Lodash, Anda dapat melakukan hal yang Anda inginkan dalam satu baris menggunakan _.set ():

_.set (object, path, value) Mengatur nilai properti jalur pada objek. Jika sebagian jalur tidak ada, itu dibuat.

https://lodash.com/docs#set

Jadi contoh Anda adalah: _.set($scope, the_string, something);


4

Hanya untuk menambahkan jawaban yang telah diberikan, berikut ini berhasil untuk saya:

HTML:

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

Dimana $indexindeks loop.

Javascript (di mana valueparameter yang diteruskan ke fungsi dan itu akan menjadi nilai $index, indeks loop saat ini):

var variable = "val"+value;
if ($scope[variable] === undefined)
{
    $scope[variable] = true;
}else {
    $scope[variable] = !$scope[variable];
}

Ini tidak ada hubungannya dengan pertanyaan, harap tetap pada topik.
Erik Honn

Maaf, mungkin ini membantu dalam membuat variabel dinamis menggunakan string. Utas ini membantu saya menulis kode di atas yang berfungsi dengan baik untuk saya.
Riaz

Jangan khawatir, ingin memberikan jawaban adalah permulaan yang baik, pastikan untuk membaca pertanyaannya terlebih dahulu :) Dalam kasus ini, ini tentang mengurai string yang tidak dikenal "abc" ke objek {a: {b: {c: ...} }}. Tetapi menangani item berulang adalah masalah umum jadi saya senang Anda menemukan sesuatu yang menyembuhkan di utas.
Erik Honn

Oh, dan seperti yang saya catat di jawaban lain, jika nilainya seharusnya benar / salah (atau tidak ditentukan) Anda bisa melewati seluruh logika dan melakukan $ scope [variabel] ===! $ Scope [variabel], karena ! undefined benar dalam javascript. Meskipun jika Anda menggunakan naskah ketikan saya curiga itu akan membuat Anda marah!
Erik Honn

3

Harap diingat: ini hanyalah JavaScript dan tidak ada hubungannya dengan Angular JS. Jadi jangan bingung tentang tanda '$' ajaib;)

Masalah utamanya adalah ini adalah struktur hierarki.

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

Ini tidak ditentukan karena "$ scope.life" tidak ada tetapi istilah di atas ingin memecahkan "arti".

Solusi seharusnya

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

atau dengan sedikit usaha lagi.

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 ']);

Karena Anda dapat mengakses objek struktural dengan

var a = {};
a.b = "ab";
console.log(a.b === a['b']);

Ada beberapa tutorial bagus tentang ini yang memandu Anda dengan baik melalui kesenangan dengan JavaScript.

Ada sesuatu tentang

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

Pergi dan cari web untuk 'angular $ apply' dan Anda akan menemukan informasi tentang fungsi $ apply. Dan Anda harus menggunakan lebih bijak dengan cara ini (jika Anda tidak alreay dengan fase $ apply).

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

3
Terima kasih atas jawabannya, tetapi pertanyaannya bukanlah mengapa "versi sederhana" tidak akan berfungsi, yang telah diketahui sejak awal. Pertanyaannya adalah apa alternatifnya. Saya khawatir kedua saran Anda tidak akan berhasil, keduanya mengharuskan Anda mengetahui struktur string sebelumnya, dan intinya adalah agar string tersebut dinamis (dan dapat menangani string arbitrer). Lihat jawaban yang diterima untuk mendapatkan solusi.
Erik Honn

1
Selain itu, tidak ada jawaban yang benar-benar menyelesaikan masalah. Yang pertama gagal pada prasyarat dasar, bahwa kita harus menetapkan $ scope.abc dan bukan ke $ scope ['abc'], dan yang kedua juga gagal dan menghasilkan hal yang sama persis dengan "versi sederhana" dari pertanyaan, hanya dengan sintaks yang tidak diperlukan, tapi mungkin itu salah ketik? :)
Erik Honn

0

Jika Anda menggunakan pustaka Lodash di bawah ini adalah cara untuk menyetel variabel dinamis dalam lingkup sudut.

Untuk mengatur nilai dalam lingkup sudut.

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

Untuk mendapatkan nilai dari lingkup sudut.

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

-1

Jika Anda mencoba melakukan apa yang saya bayangkan Anda coba lakukan, maka Anda hanya perlu memperlakukan scope seperti objek JS biasa.

Inilah yang saya gunakan untuk respons sukses API untuk larik data JSON ...

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

Sekarang {{subject}} akan mengembalikan larik nama subjek data, dan dalam contoh saya akan ada atribut cakupan untuk {{jobs}}, {{customers}}, {{staff}}, dll. Dari $ scope. pekerjaan, $ scope.customers, $ scope.staff


4
Terima kasih atas jawabannya tetapi itu tidak sama. Ini tentang membuat $ scope.subject.name dari string tanpa hard-coding $ scope.subject. Ini relevan dalam beberapa arahan di mana Anda tidak boleh mengasumsikan apa pun tentang ruang lingkup jika Anda ingin arahan dapat digunakan kembali. Juga, angular.forEach ()! Jangan biarkan jQuery menghalangi penggunaan angular: P
Erik Honn
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.