Đặt các biến phạm vi động trong AngularJs - scope. <some_string>


97

Tôi có một chuỗi mà tôi đã nhận được từ một routeParamhoặc một thuộc tính chỉ thị hoặc bất cứ thứ gì và tôi muốn tạo một biến trên phạm vi dựa trên điều này. Vì thế:

$scope.<the_string> = "something".

Tuy nhiên, nếu chuỗi chứa một hoặc nhiều dấu chấm, tôi muốn tách nó ra và thực sự "đi sâu" vào phạm vi. Vì vậy, 'foo.bar'nên trở thành $scope.foo.bar. Điều này có nghĩa là phiên bản đơn giản sẽ không hoạt động!

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

Khi đọc một biến dựa trên một chuỗi, bạn có thể nhận được hành vi này bằng cách thực hiện $scope.$eval(the_string), nhưng làm thế nào để thực hiện điều đó khi gán một giá trị?

Câu trả lời:


174

Giải pháp tôi đã tìm thấy là sử dụng $ parse .

"Chuyển đổi biểu thức Angular thành một hàm."

Nếu ai có câu trả lời hay hơn, vui lòng thêm câu trả lời mới cho câu hỏi!

Đây là ví dụ:

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
Vì vậy, điều này là đẹp! Nhưng (và hầu như luôn có một) Tôi không thể lấy $ scope. $ Apply () để phổ biến dữ liệu của mình. Tôi có thể thấy nó trong nhật ký bảng điều khiển, nhưng chế độ xem của tôi không hiển thị dữ liệu mới được thêm vào (tôi có một thanh chân trang nơi tôi hiển thị $ scope) - Có ý kiến ​​gì không?
william e schroeder

Khó biết nếu không nhìn thấy mã, nhưng suy đoán đầu tiên của tôi sẽ là footer không nằm trong cùng phạm vi. Nếu footer nằm ngoài phần tử có ng-controller = "YourController" thì nó sẽ không có quyền truy cập vào các biến của nó.
Erik Honn

3
Cảm ơn vì câu trả lời. Tôi muốn chỉ ra rằng gán cũng hoạt động với các đối tượng phức tạp, không chỉ các kiểu nguyên thủy.
Patrick Salami

1
Tại sao $ scope. $ Áp dụng cần thiết?
tội lỗiθ

Tôi thực sự không nhớ lắm. Tôi nghĩ đó là do model.assign không kích hoạt liên kết dữ liệu, vì vậy bạn cần phải áp dụng theo cách thủ công khi bạn đã hoàn thành mọi thứ cần làm. Hãy dùng thử và xem có thể loại bỏ nó hay không (có thể cũng đã thay đổi trong các phiên bản Angular mới hơn, tôi nghĩ đây là một hoặc hai phiên bản trở lại).
Erik Honn

20

Sử dụng câu trả lời của Erik, làm điểm khởi đầu. Tôi đã tìm thấy một giải pháp đơn giản hơn phù hợp với tôi.

Trong chức năng ng-click của mình, tôi có:

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

Tôi đã thử nghiệm nó có và không có $ scope. $ Áp dụng. Hoạt động chính xác mà không có nó!


13
Lưu ý rằng đây là một cái gì đó hoàn toàn khác với những gì câu hỏi là về. Mục tiêu của câu hỏi là tạo ra một biến phạm vi động có nhiều hơn 1 độ sâu dựa trên một chuỗi. Vì vậy, để tạo "scope.life.mearies" chứ không phải "scope.lifeMeaning". Sử dụng $ scope [the_string] sẽ không làm được điều đó. Và đối với trường hợp cụ thể của bạn, hãy nhớ rằng! Undefined thực sự đúng trong javascrip, vì vậy bạn thực sự có thể bỏ qua toàn bộ câu lệnh if và chỉ thực hiện $ scope [the_string] =! $ Scope [the_string] ;. Tuy nhiên, mã có thể xáo trộn một chút, vì vậy tôi không chắc liệu nó có thực sự là thứ bạn muốn hay không.
Erik Honn

@ErikHonn, thật ra, $ scope [life.mentic] = true đã làm việc cho tôi!
Jesse P Francis

1
Nó "hoạt động", nhưng trừ khi một cái gì đó thay đổi trong 1.6, nó không làm điều tương tự như câu hỏi yêu cầu. Nếu bạn thực hiện $ scope [life.mentic] = true, tên của thuộc tính sẽ là "life.mentic" và đó không phải là điều chúng tôi muốn. Chúng ta muốn một tài sản gọi là cuộc sống có một tài sản con gọi là ý nghĩa.
Erik Honn

13

Tạo biến góc động từ kết quả

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

ps. đừng quên chuyển thuộc tính $ parse vào chức năng của bộ điều khiển của bạn


5

Nếu bạn đồng ý với việc sử dụng Lodash, bạn có thể thực hiện những điều bạn muốn trong một dòng bằng cách sử dụng _.set ():

_.set (đối tượng, đường dẫn, giá trị) Đặt giá trị thuộc tính của đường dẫn trên đối tượng. Nếu một phần của đường dẫn không tồn tại, nó sẽ được tạo.

https://lodash.com/docs#set

Vì vậy, ví dụ của bạn sẽ đơn giản là: _.set($scope, the_string, something);


4

Chỉ để thêm vào các câu trả lời đã cho đã đọc, những điều sau đây phù hợp với tôi:

HTML:

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

Trong trường hợp $indexlà chỉ số vòng lặp.

Javascript ( valuetham số được truyền vào hàm ở đâu và nó sẽ là giá trị của $index, chỉ mục vòng lặp hiện tại):

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

Điều này không liên quan gì đến câu hỏi, vui lòng tiếp tục chủ đề.
Erik Honn

Xin lỗi, tôi nghĩ rằng nó có thể hữu ích trong việc tạo biến động bằng cách sử dụng chuỗi. Chủ đề này đã giúp tôi viết đoạn mã trên đang hoạt động tốt đối với tôi.
Riaz

Đừng lo lắng, muốn cung cấp câu trả lời là một khởi đầu tốt, chỉ cần đảm bảo đọc câu hỏi trước :) Trong trường hợp này là phân tích cú pháp một chuỗi không xác định "abc" thành đối tượng {a: {b: {c: ...} }}. Nhưng việc xử lý các mục lặp lại là một vấn đề phổ biến nên tôi rất vui vì bạn đã tìm thấy thứ gì đó lành mạnh trong chuỗi.
Erik Honn

Ồ, và như tôi đã lưu ý trong một câu trả lời khác, nếu các giá trị chỉ được cho là đúng / sai (hoặc không xác định), bạn chỉ có thể bỏ qua toàn bộ logic và thực hiện $ scope [biến] ===! $ Scope [biến], vì ! undefined là đúng trong javascript. Mặc dù nếu bạn đang sử dụng chữ viết, tôi nghi ngờ nó sẽ khiến bạn tức giận!
Erik Honn

3

Xin lưu ý: đây chỉ là một thứ JavaScript và không liên quan gì đến Angular JS. Vì vậy, đừng nhầm lẫn về dấu hiệu '$' kỳ diệu;)

Vấn đề chính là đây là một cấu trúc phân cấp.

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

Điều này không được xác định vì "$ scope.life" không tồn tại nhưng thuật ngữ ở trên muốn giải quyết "nghĩa".

Một giải pháp nên

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

hoặc với một chút hiệu quả hơn.

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

Vì bạn có thể truy cập một đối tượng cấu trúc với

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

Có một số hướng dẫn tốt về điều này sẽ hướng dẫn bạn tận hưởng niềm vui với JavaScript.

Có điều gì đó về

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

Truy cập và tìm kiếm trên web cho 'angle $ apply' và bạn sẽ tìm thấy thông tin về chức năng $ apply. Và bạn nên sử dụng cách này một cách khôn ngoan hơn (nếu bạn không phù hợp với giai đoạn $ apply).

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

3
Cảm ơn vì câu trả lời, nhưng câu hỏi không phải là tại sao "phiên bản đơn giản" sẽ không hoạt động, điều đó đã được biết ngay từ đầu. Câu hỏi đặt ra là giải pháp thay thế là gì. Tôi e rằng cả hai gợi ý của bạn đều không hiệu quả, cả hai đều yêu cầu bạn phải biết trước cấu trúc của chuỗi, và điểm mấu chốt là nó phải động (và có thể xử lý các chuỗi tùy ý). Xem câu trả lời được chấp nhận để biết giải pháp.
Erik Honn

1
Ngoài ra, không câu trả lời nào thực sự giải quyết được vấn đề. Điều kiện đầu tiên không thành công điều kiện tiên quyết cơ bản mà chúng ta nên gán cho $ scope.abc chứ không phải cho $ scope ['abc'] và điều kiện thứ hai cũng không thành công điều này và dẫn đến điều kiện giống hệt như "phiên bản đơn giản" từ câu hỏi, chỉ với cú pháp không cần thiết, nhưng có lẽ đó là lỗi chính tả? :)
Erik Honn

0

Nếu bạn đang sử dụng thư viện Lodash dưới đây là cách để đặt một biến động trong phạm vi góc.

Để đặt giá trị trong phạm vi góc.

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

Để lấy giá trị từ phạm vi góc.

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

-1

Nếu bạn đang cố gắng làm những gì tôi tưởng tượng là bạn đang cố gắng làm, thì bạn chỉ phải coi phạm vi như một đối tượng JS thông thường.

Đây là những gì tôi sử dụng cho phản hồi thành công API cho mảng dữ liệu 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;
    });
}

Bây giờ, {{Subject}} sẽ trả về một mảng tên chủ thể dữ liệu và trong ví dụ của tôi, sẽ có một thuộc tính phạm vi cho {{công việc}}, {{khách hàng}}, {{nhân viên}}, v.v. từ $ scope. việc làm, $ scope.customers, $ scope.staff


4
Cảm ơn vì câu trả lời nhưng đó không phải là điều tương tự. Đó là về việc tạo $ scope.subject.name từ một chuỗi mà không cần mã hóa cứng $ scope.subject. Điều này có liên quan trong một số chỉ thị nơi bạn không nên giả định bất kỳ điều gì về phạm vi nếu bạn muốn chỉ thị có thể sử dụng lại. Ngoài ra, angle.forEach ()! Đừng để jQuery cản trở việc sử dụng
angle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.