Встановлення динамічних змінних області в AngularJs - scope. <some_string>


97

У мене є рядок, який я отримав з routeParamатрибута a direktiva або будь-якого іншого, і я хочу створити змінну на області застосування на основі цього. Так:

$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 () для розповсюдження своїх даних. Я бачу це в журналі консолі, але в моєму вікні не відображаються нещодавно додані дані (у мене є колонка нижнього колонтитулу, де я показую область $) - Будь-які ідеї?
william e schroeder

Важко знати, не бачачи коду, але моя перша здогадка полягала б у тому, що колонтитул не в такому ж масштабі. Якщо нижній колонтитул знаходиться поза елементом з ng-controller = "YourController", він не матиме доступу до своїх змінних.
Ерік Гонн

3
Дякую за відповідь. Хотілося б зазначити, що присвоєння також працює зі складними об'єктами, а не лише примітивними типами.
Патрік Саламі,

1
Чому $ scope. $ Apply потрібно?
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 [змінну] ===! $ Область [змінну], оскільки ! 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. І ви повинні використовувати розумно більше таким чином (якщо ви вже не з фазою $ apply).

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

3
Дякую за відповідь, але питання полягало не в тому, чому "проста версія" не буде працювати, що було відомо з самого початку. Питання полягало в тому, яка альтернатива. Боюсь, жодна з ваших двох пропозицій не буде працювати, обидві вимагають від вас попереднього знання структури рядка, і сенс у тому, щоб вона була динамічною (і щоб мати можливість обробляти довільні рядки). Дивіться прийняту відповідь на рішення.
Ерік Хонн,

1
Крім того, жодна відповідь насправді не вирішує проблему. Перший не відповідає основній умові, яку нам слід присвоїти $ range.abc, а не $ range ['abc'], а другий також не виконує це, і в результаті виходить буквально те саме, що і "проста версія" з питання, просто з непотрібним синтаксисом, але, можливо, це помилка друку? :)
Ерік Гонн

0

Якщо ви використовуєте бібліотеку Lodash нижче, це спосіб встановити динамічну змінну в кутовій області.

Щоб встановити значення в кутовій області.

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

Тепер {{subjects}} поверне масив назв суб'єктів даних, і в моєму прикладі буде атрибут області для {{jobs}}, {{customers}}, {{staff}} тощо з $ range. вакансії, $ 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.