Festlegen dynamischer Bereichsvariablen in AngularJs - scope. <Some_string>

97

Ich habe eine Zeichenfolge, die ich von einem routeParamoder einem Direktivenattribut oder was auch immer erhalten habe, und ich möchte basierend darauf eine Variable für den Bereich erstellen. So:

$scope.<the_string> = "something".

Wenn die Zeichenfolge jedoch einen oder mehrere Punkte enthält, möchte ich sie aufteilen und tatsächlich einen Drilldown in den Bereich durchführen. So 'foo.bar'sollte werden $scope.foo.bar. Dies bedeutet, dass die einfache Version nicht funktioniert!

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

Wenn Sie eine Variable lesen, die auf einer Zeichenfolge basiert, können Sie dieses Verhalten erhalten $scope.$eval(the_string), aber wie geht es beim Zuweisen eines Werts?

Erik Honn
quelle

Antworten:

174

Die Lösung, die ich gefunden habe, ist die Verwendung von $ parse .

"Wandelt den Winkelausdruck in eine Funktion um."

Wenn jemand eine bessere hat, fügen Sie bitte eine neue Antwort auf die Frage hinzu!

Hier ist das Beispiel:

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
Erik Honn
quelle
1
Das ist also wunderschön! Aber (und es gibt fast immer einen) Ich kann den $ scope nicht bekommen. $ Apply (), um meine Daten zu verbreiten. Ich kann es in einem Konsolenprotokoll sehen, aber meine Ansicht zeigt nicht die neu hinzugefügten Daten an (ich habe eine Fußzeilenleiste, in der ich den $ scope anzeige) - Irgendwelche Ideen?
William E Schroeder
Schwer zu wissen, ohne Code zu sehen, aber meine erste Vermutung wäre, dass sich die Fußzeile nicht im selben Bereich befindet. Befindet sich die Fußzeile mit ng-controller = "YourController" außerhalb des Elements, hat sie keinen Zugriff auf ihre Variablen.
Erik Honn
3
Danke für die Antwort. Ich möchte darauf hinweisen, dass das Zuweisen auch mit komplexen Objekten funktioniert, nicht nur mit primitiven Typen.
Patrick Salami
1
Warum ist $ scope. $ Apply notwendig?
sinθ
Ich erinnere mich eigentlich nicht ganz. Ich denke, das lag daran, dass model.assign keine Datenbindung auslöst. Sie müssen sich also manuell bewerben, sobald Sie alles getan haben, was Sie tun müssen. Probieren Sie es aus und prüfen Sie, ob es möglich ist, es zu entfernen oder nicht (möglicherweise auch in neueren Versionen von Angular geändert, ich denke, dies war eine oder zwei Versionen zurück).
Erik Honn
20

Verwenden Sie Eriks Antwort als Ausgangspunkt. Ich habe eine einfachere Lösung gefunden, die für mich funktioniert hat.

In meiner ng-click-Funktion habe ich:

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

Ich habe es mit und ohne $ scope getestet. $ Apply. Funktioniert richtig ohne!

Andrew Gray
quelle
13
Beachten Sie, dass dies etwas völlig anderes ist als das, worum es bei der Frage geht. Das Ziel der Frage ist es, eine dynamische Bereichsvariable mit mehr als einer Tiefe basierend auf einer Zeichenfolge zu erstellen. Erstellen Sie also "scope.life.meaning" und nicht "scope.lifeMeaning". Die Verwendung von $ scope [the_string] führt dies nicht aus. Denken Sie für Ihren speziellen Fall daran, dass! Undefined in javascrip tatsächlich wahr ist. Sie können also die gesamte if-Anweisung überspringen und einfach $ scope [the_string] =! $ Scope [the_string]; ausführen. Könnte den Code ein wenig durcheinander bringen, daher bin ich mir nicht sicher, ob es wirklich etwas ist, das Sie wollen würden.
Erik Honn
@ErikHonn, eigentlich hat $ scope [life.meaning] = true für mich funktioniert!
Jesse P Francis
1
Es "funktioniert", aber wenn sich in 1.6 nichts ändert, funktioniert es nicht so, wie es die Frage verlangt. Wenn Sie $ scope [life.meaning] = true ausführen, lautet der Name der Eigenschaft "life.meaning", und das ist nicht das, was wir wollen. Wir wollen eine Eigenschaft namens Leben, die eine untergeordnete Eigenschaft namens Bedeutung hat.
Erik Honn
13

Erstellen Sie aus den Ergebnissen dynamische Winkelvariablen

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

ps. Vergessen Sie nicht, das Attribut $ parse an die Funktion Ihres Controllers zu übergeben

Demodave
quelle
5

Wenn Sie mit Lodash einverstanden sind, können Sie mit _.set () das, was Sie wollten, in einer Zeile ausführen:

_.set (Objekt, Pfad, Wert) Legt den Eigenschaftswert des Pfads für das Objekt fest. Wenn ein Teil des Pfads nicht vorhanden ist, wird er erstellt.

https://lodash.com/docs#set

Ihr Beispiel wäre also einfach: _.set($scope, the_string, something);

Nördlicher Stern
quelle
4

Nur um bereits gegebene Antworten hinzuzufügen, hat Folgendes für mich funktioniert:

HTML:

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

Wo $indexist der Schleifenindex?

Javascript (wobei valueder Parameter an die Funktion übergeben wird und der Wert des $indexaktuellen Schleifenindex ist):

var variable = "val"+value;
if ($scope[variable] === undefined)
{
    $scope[variable] = true;
}else {
    $scope[variable] = !$scope[variable];
}
Riaz
quelle
Dies hat nichts mit der Frage zu tun, bitte bleiben Sie beim Thema.
Erik Honn
Entschuldigung, ich dachte, es könnte beim Erstellen dynamischer Variablen mithilfe von Zeichenfolgen hilfreich sein. Dieser Thread hat mir geholfen, den obigen Code zu schreiben, der für mich gut funktioniert.
Riaz
Keine Sorge, Antworten geben zu wollen ist ein guter Anfang, lesen Sie zuerst die Frage :) In diesem Fall geht es darum, eine unbekannte Zeichenfolge "abc" für das Objekt {a: {b: {c: ...} zu analysieren. }}. Der Umgang mit sich wiederholenden Elementen ist jedoch ein häufiges Problem. Ich bin froh, dass Sie im Thread etwas Heilvolles gefunden haben.
Erik Honn
Oh, und wie ich bei einer anderen Antwort bemerkt habe, wenn die Werte nur wahr / falsch (oder undefiniert) sein sollen, können Sie einfach die gesamte Logik überspringen und $ scope [Variable] ===! $ Scope [Variable] ausführen, da ! undefined ist wahr in Javascript. Obwohl, wenn Sie Typoskript verwenden, ich vermute, dass es sauer auf Sie werden würde!
Erik Honn
3

Bitte beachten Sie: Dies ist nur eine JavaScript-Sache und hat nichts mit Angular JS zu tun. Also sei nicht verwirrt über das magische '$' Zeichen;)

Das Hauptproblem ist, dass dies eine hierarchische Struktur ist.

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

Dies ist undefiniert, da "$ scope.life" nicht vorhanden ist, der obige Begriff jedoch "Bedeutung" lösen möchte.

Eine Lösung sollte sein

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

oder mit etwas mehr Efford.

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

Da kann man mit auf ein Strukturobjekt zugreifen

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

Es gibt mehrere gute Tutorials dazu, die Sie gut durch den Spaß mit JavaScript führen.

Da ist etwas an der

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

Durchsuchen Sie das Web nach "Angular $ Apply" und Sie finden Informationen zur $ Apply-Funktion. Und Sie sollten es weise mehr auf diese Weise verwenden (wenn Sie nicht bereits mit einer $ apply-Phase vertraut sind).

$scope.$apply(function (){
    do...somthing...bla...bla
})
Raxa
quelle
3
Danke für die Antwort, aber die Frage war nicht, warum die "einfache Version" nicht funktionieren würde, das war von Anfang an bekannt. Die Frage war, was die Alternative war. Ich befürchte, keiner Ihrer beiden Vorschläge wird funktionieren. Beide erfordern, dass Sie die Struktur der Zeichenfolge im Voraus kennen, und es geht darum, dass sie dynamisch ist (und in der Lage ist, mit beliebigen Zeichenfolgen umzugehen). In der akzeptierten Antwort finden Sie eine Lösung.
Erik Honn
1
Außerdem löst keine der Antworten das Problem. Der erste scheitert an der Grundvoraussetzung, dass wir $ scope.abc und nicht $ scope ['abc'] zuweisen sollten, und der zweite scheitert ebenfalls daran und führt buchstäblich zu genau dem gleichen Ergebnis wie die "einfache Version" aus dem Frage, nur mit nicht benötigter Syntax, aber vielleicht ist das ein Tippfehler? :)
Erik Honn
0

Wenn Sie die unten stehende Lodash-Bibliothek verwenden, können Sie eine dynamische Variable im Winkelbereich festlegen.

Festlegen des Werts im Winkelbereich.

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

Um den Wert aus dem Winkelbereich zu erhalten.

_.get($scope, 'life.meaning')
Sagar Vaghela
quelle
-1

Wenn Sie versucht haben, das zu tun, was ich mir vorgestellt habe, müssen Sie den Bereich nur wie ein normales JS-Objekt behandeln.

Dies ist, was ich für eine API-Erfolgsantwort für JSON-Datenarray verwende ...

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

Jetzt gibt {{subject}} ein Array von Namen der betroffenen Person zurück, und in meinem Beispiel gibt es ein Bereichsattribut für {{jobs}}, {{customers}}, {{staff}} usw. von $ scope. Jobs, $ scope.customers, $ scope.staff

Kieran McKewen
quelle
4
Danke für die Antwort, aber das ist nicht dasselbe. Es geht darum, $ scope.subject.name aus einer Zeichenfolge zu erstellen, ohne $ scope.subject fest zu codieren. Dies ist in einigen Richtlinien relevant, in denen Sie nichts über den Geltungsbereich annehmen sollten, wenn die Richtlinie wiederverwendbar sein soll. Auch angle.forEach ()! Lassen Sie sich von jQuery nicht daran hindern, Winkel zu verwenden: P
Erik Honn