2015-06-20 85 views
4

說我們有這個表達式AngularJS看着表達

$scope.showButton = users.is_admin() && !document.is_provided; 

然後在相同的控制器,你有一個按鈕,更新的Document.is_provided值:

<button ng-click="document.is_provided = true;">Provide document</button> 

的問題是,$scope.showButton現在應該改變了,但並沒有改變。

更新時間: Plnkr顯示簡單的問題:http://plnkr.co/edit/Qk2jnHAmqsrNXSAjDYEk?p=preview

+0

回答更新。 – outoftime

+0

爲什麼你認爲'$ scope.showButton'的值應該改變? – zeroflagL

+0

我需要一種方法來重新計算..所以我要求最好的方法來做到這一點使用角度(而不是包裝它的功能,然後調用它,每次我改變它的值) –

回答

4

我想添加到squiroid的回答,爲什麼給你解釋作品。我會提供一個非常簡單的方法讓你理解,因爲這對我來說也是一個非常普遍的問題,當我開始時。

Angular有一些東西叫Digest循環。它是連續調用的一系列函數,以確保如果變量A與另一個變量B雙向綁定(例如使用ng-model),它們總是保持同步(即始終具有相同的值)。角度提供的函數(或服務,通常以$開頭,如$ timeout等)自動啓動摘要循環

因此,假設您有一個變量A並且已將它綁定到$ scope變量B ,它等於一個變量C.你會期望C也被綁定到A,對吧?因爲你認爲當你改變C時,B應該改變,所以A也應該改變。但是這隻有在你開始摘要循環時纔有可能。循環將查找需要更新的變量,並將更新它們。然而,通過簡單地改變C的值,你永遠不會觸發摘要循環,所以你的改變永遠不會傳播到A.

當你在$ watch中放置一個變量時你會做什麼(如$建議) ,你會強制開始一個摘要循環。所以現在當你改變C時,你開始了這個循環,它追蹤到它需要更新A,這就是它工作的原因。

在你的例子中,$ scope.showButton被綁定到document.is_provided。現在,您正在使用非角度函數來更改document.is_provided的值。這意味着您不會觸發摘要循環,這意味着您的更改永遠不會傳播到$ scope.showButton。因此,showButton始終保持爲假。

和當然,一個例子來幫助你理解: http://jsbin.com/vojoso/edit?js,console,output

看控制檯。我已經添加了日誌來幫助你理解。 註釋$ watch語句,看看會發生什麼。 試着理解它,然後自己做,你會得到它。

希望我幫助:)

+0

非常感謝!實際上我不明白的是他們如何能夠在沒有$ watch的情況下工作......並使用var main = this; 有什麼想法? –

+0

我不確定。我認爲他們以某種方式保存了控制器的狀態?我不得不說,我不認爲我見過這種代碼。抱歉。 :/ – madebysid

3

我不知道,但你可以在上面看: -

$scope.$watch(function(){ 
    return Users.is_admin() && !Document.is_provided; 
},fuction(newVal){ 
$scope.showButton =newVal; 
}); 

希望它能幫助:)

+0

這也適用!但我更願意看看我們如何才能使它工作,而不需要$ watch –

+0

我不明白這一點。這裏正在觀看的是什麼?介意解釋一下? – geckob

+1

@geckob如果返回值爲true(這意味着Users.is_admin()和!Document.is_provided都是true),則第一個參數是應該被監視的表達式(在這種情況下,它是一個返回true或false的函數) )$ scope.showButton變爲true。所以Angular監督Users.is_admin()和Document.is_provided這兩個「值得關注」的值。通常情況下,你只需要一個值,例如$ scope。$ watch('scopesVariable',function(newVal,oldVal){...}),但是通常也可以定義一個函數,參見https:// docs。 angularjs.org/api/ng/type/$rootScope.Scope – ilmgb

2

這裏是關於好文章$scope.$watch,它應該有助於瞭解如何解決您的問題。

它需要更大的答案添加代碼,這將解釋Document變量和您的REST服務。

UPD:我看到你改變了你原來的問題。我想你對控制器有麻煩。儘量不要使用$scope含蓄,使用data屬性爲悲傷angular code style

還顯示了部分在你模板,你連接控制器。

UPD 2:你的我的話有些誤會,所以我修改了plunker example

的index.html

<html ng-app="plunker"> 
    <body ng-controller="MainController as main"> 

    <div ng-show="main.data.document.is_provided">visible</div> 
    <button ng-click="main.hide()">Hide</button> 

    <script data-require="angular[email protected]" 
      src="https://code.angularjs.org/1.4.1/angular.js" 
      data-semver="1.4.1"></script> 
    <script src="app.js"></script> 
    </body> 
</html> 

app.js

angular 
    .module('plunker', []) 
    .controller('MainController', MainController); 

function MainController() { 
    var main = this; 

    this.data = { 
     document: { 
     is_provided: true 
     } 
    }; 

    this.hide = hide; 

    function hide() { 
     main.data.document.is_provided = false; 
    } 
} 

你有一個問題在裏面ng-click,因爲應該有功能執行。此外,您正在使用ng-if而不是ng-show

+0

謝謝你的幫助。我創建了一個工作plnkr向您顯示問題: http://plnkr.co/edit/Qk2jnHAmqsrNXSAjDYEk?p=preview –

+0

OP顯式使用'$ scope'。你的意思是什麼'data'屬性? – zeroflagL

+0

我在他提到它之後加了他們 –

2

最好的方法(imho)來處理這種問題: 在您的看法中使用{{ anyObject | json }}

這樣你就知道你正在使用的引用和對象是否在你的範圍內。使用| json可以在您的對象存在但空時爲您提供讚譽{}。如果您的物體不在您的示波器中,請注意已「印製」。

在你的情況,身體標記更改爲: <body ng-controller="MainCtrl as mainCtrl">

然後,這個控制器添加的HTML中:

DATA: {{mainCtrl | json}} 

所以,現在你看到你的變數!而且你也看到點擊按鈕不會改變布爾變量。

一些額外的調試和重寫,這個工程:

app.controller('MainCtrl', function($scope) { 

var main = this; 

this.data = { 
    document: { 
    is_provided: true 
    } 
}; 



$scope.hide = function() { 
    console.log(main); 
    main.data.document.is_provided = !main.data.document.is_provided; 
} 
}); 

和: <button ng-click="hide()">Hide</button>(注意括號)

+1

請注意,如果您將它包裝在'pre'標籤中:'

{{ data | json }}
',那麼您可以通過該調試技巧獲得更好的可讀性。 – JcT

+0

@Sander_P謝謝你的回答,但我仍然不明白你爲什麼使用'var main = this'有沒有一篇文章可以指導我完成這個任務?我現在明白它是如何工作的,但我從未見過它。 –

+0

這是在我的代碼中的原因是因爲它在你的代碼:)我個人儘量避免在我的控制器中儘可能使用代碼,並把它放在指令(DOM邏輯)或服務(業務邏輯)。嘗試使用帶有** link **函數的指令,並使用$ scope而不是「this」。 –