Impostazione delle variabili di ambito dinamico in AngularJs - scope. <some_string>


97

Ho una stringa che ho ottenuto da un routeParamo un attributo di direttiva o qualsiasi altra cosa, e voglio creare una variabile sull'ambito basata su questo. Così:

$scope.<the_string> = "something".

Tuttavia, se la stringa contiene uno o più punti, voglio dividerla e "approfondire" effettivamente l'ambito. Così 'foo.bar'dovrebbe diventare $scope.foo.bar. Ciò significa che la versione semplice non funzionerà!

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

Quando leggi una variabile basata su una stringa puoi ottenere questo comportamento facendo $scope.$eval(the_string), ma come farlo quando assegni un valore?

Risposte:


174

La soluzione che ho trovato è usare $ parse .

"Converte l'espressione angolare in una funzione."

Se qualcuno ne ha uno migliore, aggiungi una nuova risposta alla domanda!

Ecco l'esempio:

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
Quindi questo è bellissimo! Ma (e ce n'è quasi sempre uno) non riesco a ottenere $ scope. $ Apply () per propagare i miei dati. Posso vederlo in un registro della console, ma la mia vista non mostra i dati appena aggiunti (ho una barra a piè di pagina in cui mostro $ scope) - Qualche idea?
william e schroeder

Difficile da sapere senza vedere il codice, ma la mia prima ipotesi sarebbe che il piè di pagina non sia nello stesso ambito. Se il piè di pagina è all'esterno dell'elemento con ng-controller = "YourController", non avrà accesso alle sue variabili.
Erik Honn

3
Grazie per la risposta. Vorrei sottolineare che assign funziona anche con oggetti complessi, non solo con tipi primitivi.
Patrick Salami

1
Perché è necessario $ scope. $ Apply?
sinθ

In realtà non ricordo bene. Penso che fosse perché model.assign non attiva l'associazione dei dati, quindi è necessario applicare manualmente una volta che hai fatto tutto ciò che devi fare. Provalo e vedi se è possibile rimuoverlo o meno (potrebbe essere cambiato anche nelle versioni più recenti di Angular, penso che questa fosse una o due versioni precedenti).
Erik Honn

20

Usando la risposta di Erik, come punto di partenza. Ho trovato una soluzione più semplice che ha funzionato per me.

Nella mia funzione ng-click ho:

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

L'ho testato con e senza $ scope. $ Apply. Funziona correttamente senza di essa!


13
Nota che questo è qualcosa di completamente diverso da quello di cui tratta la domanda. L'obiettivo della domanda è creare una variabile di ambito dinamico con più di 1 profondità basata su una stringa. Quindi per creare "scope.life.meaning" e non "scope.lifeMeaning". L'uso di $ scope [the_string] non lo farà. E per il tuo caso specifico, ricorda che! Undefined è effettivamente vero in javascrip, quindi potresti saltare l'intera istruzione if e fare solo $ scope [the_string] =! $ Scope [the_string] ;. Potrebbe confondere un po 'il codice, quindi non sono sicuro che sia davvero qualcosa che vorresti.
Erik Honn

@ErikHonn, in realtà, $ scope [life.meaning] = true ha funzionato per me!
Jesse P Francis

1
"Funziona", ma a meno che non sia cambiato qualcosa nella 1.6 non fa la stessa cosa richiesta dalla domanda. Se fai $ scope [life.meaning] = true il nome della proprietà sarà "life.meaning", e non è quello che vogliamo. Vogliamo una proprietà chiamata vita che abbia una proprietà figlia chiamata significato.
Erik Honn

13

Crea variabili angolari dinamiche dai risultati

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

ps. non dimenticare di passare l'attributo $ parse nella funzione del tuo controller


5

Se sei d'accordo con l'uso di Lodash, puoi fare la cosa che volevi in ​​una riga usando _.set ():

_.set (oggetto, percorso, valore) Imposta il valore della proprietà del percorso sull'oggetto. Se una porzione di percorso non esiste viene creata.

https://lodash.com/docs#set

Quindi il tuo esempio sarebbe semplicemente: _.set($scope, the_string, something);


4

Solo per aggiungere alle risposte già fornite, il seguente ha funzionato per me:

HTML:

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

Dov'è $indexl'indice del ciclo.

Javascript (dove valueè il parametro passato alla funzione e sarà il valore di $index, indice del ciclo corrente):

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

Questo non ha nulla a che fare con la domanda, per favore rimani in argomento.
Erik Honn

Mi dispiace, ho pensato che potrebbe aiutare nella creazione di variabili dinamiche utilizzando le stringhe. Questo thread mi ha aiutato a scrivere il codice sopra che funziona bene per me.
Riaz

Nessun problema, voler fornire risposte è un buon inizio, assicurati solo di leggere prima la domanda :) In questo caso si tratta di analizzare una stringa sconosciuta "abc" per l'oggetto {a: {b: {c: ...} }}. Ma la gestione degli elementi ripetuti è un problema comune, quindi sono contento che tu abbia trovato qualcosa di sano nel thread.
Erik Honn

Oh, e come ho notato in un'altra risposta, se i valori dovrebbero essere veri / falsi (o non definiti) potresti semplicemente saltare l'intera logica e fare $ scope [variabile] ===! $ Scope [variabile], poiché ! undefined è vero in javascript. Sebbene tu stia usando un dattiloscritto, sospetto che ti arrabbierei!
Erik Honn

3

Tieni presente che questa è solo una cosa JavaScript e non ha nulla a che fare con Angular JS. Quindi non essere confuso riguardo al magico segno '$';)

Il problema principale è che questa è una struttura gerarchica.

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

Questo non è definito perché "$ scope.life" non esiste ma il termine sopra vuole risolvere "significato".

Una soluzione dovrebbe essere

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

o con un po 'più di impegno.

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

Dal momento che puoi accedere a un oggetto strutturale con

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

Ci sono molti buoni tutorial su questo argomento che ti guidano nel divertimento con JavaScript.

C'è qualcosa in

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

Vai e cerca nel web "angular $ apply" e troverai informazioni sulla funzione $ apply. E dovresti usarlo saggiamente in questo modo (se non sei già pronto con una fase $ apply).

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

3
Grazie per la risposta, ma la domanda non era perché la "versione semplice" non avrebbe funzionato, questo era noto fin dall'inizio. La domanda era quale fosse l'alternativa. Temo che nessuno dei tuoi due suggerimenti funzionerà, entrambi richiedono di conoscere in anticipo la struttura della stringa, e il punto è che sia dinamico (e che sia in grado di gestire stringhe arbitrarie). Vedi la risposta accettata per una soluzione.
Erik Honn

1
Inoltre, nessuna delle due risposte risolve effettivamente il problema. Il primo fallisce il prerequisito di base, che dovremmo assegnare a $ scope.abc e non a $ scope ['abc'], e anche il secondo fallisce e risulta letteralmente la stessa identica cosa della "versione semplice" dal domanda, solo con una sintassi non necessaria, ma forse è un errore di battitura? :)
Erik Honn

0

Se stai usando la libreria Lodash qui sotto è il modo per impostare una variabile dinamica nell'ambito angolare.

Per impostare il valore nell'ambito angolare.

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

Per ottenere il valore dall'ambito angolare.

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

-1

Se stavi cercando di fare quello che immagino stavi cercando di fare, allora devi solo trattare l'ambito come un normale oggetto JS.

Questo è ciò che utilizzo per una risposta di successo dell'API per l'array di dati 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;
    });
}

Ora {{subject}} restituirà un array di nomi di soggetti dei dati e nel mio esempio ci sarebbe un attributo scope per {{jobs}}, {{customers}}, {{staff}}, ecc. Da $ scope. jobs, $ scope.customers, $ scope.staff


4
Grazie per la risposta ma non è la stessa cosa. Si tratta di creare $ scope.subject.name da una stringa senza l'hardcoding di $ scope.subject. Ciò è rilevante in alcune direttive in cui non si dovrebbe assumere nulla sull'ambito se si desidera che la direttiva sia riutilizzabile. Inoltre, angular.forEach ()! Non lasciare che jQuery ostacoli l'uso di angular: P
Erik Honn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.