AngularJS指令Link函数中点击按钮如何更新attrs切换CSS类?
Hey there! I see exactly where you're stuck—your directive's link function only runs once when the app boots up, so it never catches the updated result value after you click the button. Let's fix this with a couple of simple, effective solutions.
问题根源
The link function executes only one time when the directive is first attached to the element. At that point, $attrs.result is still its initial empty value (since score.result hasn't been set yet). When you click the button and update score.result, the directive has no way to know the value changed, so it never updates the CSS class.
解决方案1:用$attrs.$observe监听插值属性变化
Since you're using interpolation ({{ score.result }}) for the result attribute, Angular's $attrs.$observe method is tailor-made for tracking changes to this value. It's specifically designed to watch attributes that use double curly brace syntax.
Update your directive code like this:
function displayResult () { return { restrict: 'A', link: function ($scope, $element, $attrs) { // Set initial grey class $element.addClass('grey'); // Watch for changes to the result attribute $attrs.$observe('result', (newVal, oldVal) => { // Remove the old status class if it exists if (oldVal) { $element.removeClass(oldVal); } // Update classes based on new value if (newVal) { $element.removeClass('grey'); $element.addClass(newVal); } else { // Fall back to grey if no result is set $element.addClass('grey'); } }); } }; }; angular .module('app') .directive('displayResult', displayResult);
This method works with your existing HTML—no changes needed there. It'll automatically track updates to {{ score.result }} and adjust the CSS classes accordingly.
解决方案2:使用隔离作用域绑定属性
A more Angular-idiomatic approach is to create an isolated scope for the directive and bind the result property directly. This lets you watch the scope variable for changes cleanly.
Step 1: Update the directive code
function displayResult () { return { restrict: 'A', // Isolate scope with two-way binding for result scope: { result: '=' }, link: function ($scope, $element) { // Set initial grey class $element.addClass('grey'); // Watch the scope's result variable $scope.$watch('result', (newVal, oldVal) => { if (oldVal) { $element.removeClass(oldVal); } if (newVal) { $element.removeClass('grey'); $element.addClass(newVal); } else { $element.addClass('grey'); } }); } }; }; angular .module('app') .directive('displayResult', displayResult);
Step 2: Adjust the HTML binding
Since we're using scope binding now, remove the interpolation syntax from the result attribute:
<div display-result class="grey" result="score.result"> <h4> {{ score.message }} </h4> </div>
额外优化小技巧
To avoid messy class conflicts, you can clear all possible status classes before adding the new one:
$attrs.$observe('result', (newVal) => { $element.removeClass('grey win lose draw'); $element.addClass(newVal || 'grey'); });
This ensures you always start fresh and apply only the correct class for the current state.
Also, consider adding an initial value for this.result in your controller:
function ScoreController () { this.message = "The game is about to start!"; this.scoreFrance = 0; this.scoreArgentine = 0; this.test = "France - Argentine"; this.color = ""; this.result = ""; // Add this line for clearer initial state // ... rest of your code };
内容的提问来源于stack exchange,提问作者Olivier Girardot

