Установка переменных динамической области видимости в AngularJs - scope. <some_string>


97

У меня есть строка, полученная из 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), но как это сделать при присвоении значения?

Ответы:


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
Так это красиво! Но (а он почти всегда есть) я не могу получить $ scope. $ Apply () для распространения моих данных. Я вижу это в журнале консоли, но в моем представлении не отображаются только что добавленные данные (у меня есть нижний колонтитул, где я показываю $ scope) - Есть идеи?
william e schroeder

Трудно узнать, не видя кода, но я предполагаю, что нижний колонтитул не в той же области. Если нижний колонтитул находится за пределами элемента с ng-controller = "YourController", он не будет иметь доступа к своим переменным.
Эрик Хонн,

3
Спасибо за ответ. Хочу отметить, что assign также работает со сложными объектами, а не только с примитивными типами.
Патрик Салами

1
Почему необходимо применять $ scope. $?
sinθ

На самом деле я не совсем помню. Я думаю, это потому, что model.assign не запускает привязку данных, поэтому вам нужно применить вручную, как только вы сделаете все, что вам нужно сделать. Попробуйте и посмотрите, можно ли его удалить или нет (возможно, он также изменился в более новых версиях Angular, я думаю, это была одна или две версии назад).
Эрик Хонн

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.life.meaning», а не «scope.lifeMeaning». Использование $ scope [the_string] этого не сделает. И для вашего конкретного случая помните, что! Undefined на самом деле истинно в javascrip, поэтому вы можете пропустить весь оператор if и просто выполнить $ scope [the_string] =! $ Scope [the_string] ;. Возможно, код может немного запутаться, поэтому я не уверен, действительно ли это то, что вам нужно.
Эрик Хонн,

@ErikHonn, на самом деле, у меня $ scope [life.meaning] = true сработало!
Джесси П. Фрэнсис

1
Он «работает», но если что-то не изменилось в 1.6, он не делает того же, о котором спрашивает вопрос. Если вы сделаете $ scope [life.meaning] = true, имя свойства будет "life.meaning", а это не то, что мы хотим. Нам нужно свойство под названием жизнь, у которого есть дочернее свойство под названием значение.
Эрик

13

Создать динамические угловые переменные из результатов

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

пс. не забудьте передать атрибут $ parse в функцию вашего контроллера


5

Если вас устраивает использование Lodash, вы можете сделать то, что хотели, в одной строке, используя _.set ():

_.set (объект, путь, значение) Устанавливает значение свойства пути для объекта. Если часть пути не существует, она создается.

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

Это не имеет ничего общего с вопросом, пожалуйста, продолжайте тему.
Эрик Хонн

Извините, подумал, что это может помочь в создании динамических переменных с использованием строк. Эта ветка помогла мне написать приведенный выше код, который у меня отлично работает.
Riaz

Не беспокойтесь, желание дать ответы - хорошее начало, просто обязательно сначала прочтите вопрос :) В данном случае речь идет о синтаксическом разборе неизвестной строки «abc» на объект {a: {b: {c: ...} }}. Но обработка повторяющихся элементов - обычная проблема, поэтому я рад, что вы нашли что-то полезное в этой ветке.
Эрик Хонн,

О, и как я отмечал в другом ответе, если значения должны быть истинными / ложными (или неопределенными), вы можете просто пропустить всю логику и выполнить $ scope [variable] ===! $ Scope [variable], поскольку ! undefined истинно в javascript. Хотя, если вы используете машинописный текст, я подозреваю, что он на вас разозлится!
Эрик Хонн,

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. И вам следует более разумно использовать этот способ (если у вас еще нет фазы применения $).

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

3
Спасибо за ответ, но вопрос был не в том, почему «простая версия» не будет работать, это было известно с самого начала. Вопрос в том, какая альтернатива. Я боюсь, что ни одно из ваших двух предложений не сработает, оба требуют, чтобы вы знали структуру строки заранее, и дело в том, чтобы она была динамической (и чтобы иметь возможность обрабатывать произвольные строки). См. Принятый ответ для решения.
Erik Honn

1
Кроме того, ни один из ответов не решает проблему. Первый не соответствует основному предварительному условию, которое мы должны присвоить $ scope.abc, а не $ scope ['abc'], а второй также не соответствует этому и приводит к тому же результату, что и «простая версия» из вопрос, просто с ненужным синтаксисом, но, может быть, это опечатка? :)
Erik Honn

0

Если вы используете библиотеку Lodash, ниже представлен способ установки динамической переменной в области angular.

Чтобы установить значение в угловой области.

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

Чтобы получить значение из угловой области.

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

-1

Если вы пытались сделать то, что, как я полагаю, вы пытались сделать, тогда вам нужно только рассматривать область видимости как обычный объект JS.

Это то, что я использую для успешного ответа API для массива данных 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;
    });
}

Теперь {{subject}} вернет массив имен субъектов данных, и в моем примере будет атрибут scope для {{jobs}}, {{customers}}, {{staff}} и ​​т. Д. Из $ scope. вакансии, $ scope.customers, $ scope.staff


4
Спасибо за ответ, но это не одно и то же. Речь идет о создании $ scope.subject.name из строки без жесткого кодирования $ scope.subject. Это актуально в некоторых директивах, где вы не должны делать никаких предположений относительно области действия, если хотите, чтобы директива могла использоваться повторно. Также angular.forEach ()! Не позволяйте jQuery мешать использованию angular: P
Эрик Хонн
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.