The $watch function in AngularJS is used to monitor changes on the $scope object. If the input you are watching is not connected to the same $scope property that is being monitored, the watch listener will only be triggered once during initialization.
To help understand how $watch, data binding, and $scope interact, consider the following representation of your scope (even though it is currently empty due to lack of input):
{
shizzle: { // <--- The property being watched
$valid: false,
whatev: {
valid: false
}
},
whatev: "" // <--- The object that changes when you input into the <input>
}
As shown, although 'shizzle' is watched, it remains unchanged, causing the watch listener to execute only once.
Here is an updated version of your plunker that binds the watcher to the input's model and records all changes for illustration:
http://plnkr.co/edit/AbCdEfGhIjKlMnOpQrSt?p=preview
NOTE: To monitor the $valid attribute that Angular is updating, modify the following line:
scope.$watch(attrs.name, function(newVal, oldVal) {
console.log(newVal);
}, true);
to this:
scope.$watch("shizzle.$valid", function(newVal, oldVal) {
console.log(newVal);
}, true);