AngularJS: Why is ng-click not setting the variable as the value obtained from ng-repeat?
I am trying to give an application a way to set a font for a piece of text based on a list of fonts from Google Fonts.
Here's what I have:
<ul ng-init='headerFont="mono"'>
<li ng-repeat='font in fonts' style='font-family: {{font}};' ng-click='headerFont = font'>{{font}}
</li>
</ul>
and then later:
<h1 style='font-family: {{headerFont}};'>Header</h1>
and in the controller in my js file:
$scope.fonts = [...an array of font names...]
Originally, instead of ng-repeat
on, <li>
I used:
<select ng-model='headerFont' style='font-family: {{headerFont}};'>
<option ng-repeat='font in fonts' style='font-family:{{font}};'>{{font}}
</option>
</select>
And it worked the way I wanted it to. But I wanted to try using a scrollable list instead of a dropdown menu, because the menu <select>
in mobile browsers does not support changing the fonts of individual options, and it is important for me that the fonts can be previewed before Selection. I figured I could just use ng-click
to set the value headerFont
, but it doesn't do anything (no error appears in the console or whatever. It's just that nothing happens.) Does anyone know why?
source to share
The problem is that ngRepeat creates a child scope for each iteration, so ngClick actually changes the local child variable headerFont
.
One possible solution is to explicitly specify the parent scope:
var app = angular.module('demo', []);
app.controller('demoController', function($scope) {
$scope.fonts = ['Arial', 'Times New Roman', 'Verdana', 'mono'];
})
<script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.3/angular.js" data-semver="1.4.3"></script>
<div ng-app="demo" ng-controller="demoController">
<h1 style='font-family: {{headerFont}};'>Header</h1>
<ul ng-init='headerFont="mono"'>
<li ng-repeat='font in fonts' style='font-family: {{font}};' ng-click='$parent.headerFont = font'>{{font}}</li>
</ul>
</div>
source to share
Everyone ng-repeat
creates a new area. ng-click
changes headerFont
in its area without touching headerFont
the top level.
You can create a dictionary at the top level to prevent the child object from floating:
<ul ng-init="top = {'headerFont':'mono'}">
<li ng-repeat='font in fonts'
style='font-family: {{font}};'
ng-click='top.headerFont = font'>
{{font}} / {{top.headerFont}}
</li>
</ul>
source to share