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?
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>
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>
Demo: http://plnkr.co/edit/77zesZsBgYpZUDWciY18?p=preview