Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created July 9, 2013 13:52
What A Select $watch() Teaches Me About ngModel And AngularJS
<!doctype html>
<html ng-app="Demo" ng-controller="AppController">
<head>
<meta charset="utf-8" />
<title>
What A Select $watch() Teaches Me About ngModel And AngularJS
</title>
</head>
<body>
<h1>
What A Select $watch() Teaches Me About ngModel And AngularJS
</h1>
<p>
Helena Bonham Carter is {{ helena.quality }}!
</p>
<!-- Set value via Select / ngOptions. -->
<p>
<select
ng-model="form.quality"
ng-options="q.label for q in qualities">
</select>
</p>
<!-- Set value explicitly on data-model. -->
<p>
<a ng-click="setStunning()">Stunning</a> or
<a ng-click="setBeautiful()">Beautiful</a>
</p>
<!-- Load jQuery and AngularJS from the CDN. -->
<script
type="text/javascript"
src="//code.jquery.com/jquery-2.0.0.min.js">
</script>
<script
type="text/javascript"
src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js">
</script>
<script type="text/javascript">
// Create an application module for our demo.
var app = angular.module( "Demo", [] );
// -------------------------------------------------- //
// -------------------------------------------------- //
// I control the root of the application.
app.controller(
"AppController",
function( $scope ) {
// I define the initial state of Helena.
$scope.helena = {
name: "Helena",
quality: "beautiful"
};
// I define the possible qualities that can be
// selected in the dropdown menu.
$scope.qualities = [
{
label: "Beautiful",
value: "beautiful"
},
{
label: "Stunning",
value: "simply stunning"
},
{
label: "Dark",
value: "dark and mysterious"
},
{
label: "Exotic",
value: "exotic"
},
{
label: "Silly (disabled)",
value: "silly"
}
];
// I set up the initial form values for the ngModel
// bindings. This allows me to examine the form values
// before I *choose* to have the changes propagated
// throughout my view-model.
$scope.form = {
quality: getQualityOptionByValue( "beautiful" )
};
// I watch the data-model for changes such that I may
// synchronize the form values.
$scope.$watch(
"helena.quality",
function( newValue, oldValue ) {
// Ignore initial setup.
if ( newValue === oldValue ) {
return;
}
console.log( "$watch: helena.quality changed." );
// Ignore if form already mirrors new value.
if ( $scope.form.quality.value === newValue ) {
return;
}
$scope.form.quality = getQualityOptionByValue( newValue );
}
);
// I watch the form for changes such that I may
// synchronize the data-model.
$scope.$watch(
"form.quality",
function( newValue, oldValue ) {
// Ignore initial setup.
if ( newValue === oldValue ) {
return;
}
console.log( "$watch: form.quality changed." );
// Ignore if the data-model already mirrors
// the new value defined in the form.
if ( $scope.helena.quality === newValue.value ) {
return;
}
// Ignore "invalid" form selection. This isn't
// a likely use-case; however, it does point
// out a possible benefit of this two-way
// data-binding gatekeeper.
if ( newValue.value === "silly" ) {
// Reset to the old value!!!
return( $scope.form.quality = oldValue );
}
$scope.helena.quality = newValue.value;
}
);
// ---
// PUBLIC METHODS.
// ---
// I define Helena as beautiful.
$scope.setBeautiful = function() {
$scope.helena.quality = "beautiful";
};
// I define Helena as stunning!
$scope.setStunning = function() {
$scope.helena.quality = "simply stunning";
};
// ---
// PRIVATE METHODS.
// ---
// I return the select-option with the given value.
function getQualityOptionByValue( value ) {
for ( var i = 0 ; i < $scope.qualities.length ; i++ ) {
if ( $scope.qualities[ i ].value === value ) {
return( $scope.qualities[ i ] );
}
}
return( null );
}
}
);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment