2

As an exercise, I'm creating inputs for color values using both RGB and hex.

html:

<form ng-controller="myCtrl">
    R:<input ng-model="rChannel" type="number" min="0" max="255" required></input>
    G:<input ng-model="gChannel" type="number" min="0" max="255" required></input>
    B:<input ng-model="bChannel" type="number" min="0" max="255" required></input>

    hex: #<input ng-model="hexColor" type="text" required></input>
</form>

js:

function myCtrl($scope) {
    $scope.$watch('[rChannel, gChannel, bChannel]',
              function() {
                $scope.hexColor = rgbToHex($scope.rChannel, $scope.gChannel, $scope.bChannel)
              },
              true);

    $scope.$watch('hexColor',
              function() {
                var rgbArr = hexToRgbArray($scope.hexColor);
                $scope.rChannel =  rgbArr[0];
                $scope.gChannel =  rgbArr[1];
                $scope.bChannel =  rgbArr[2];
              });
}

http://jsfiddle.net/F545z/

It works... with one big hiccup. The moment any one input value goes invalid (an empty string, or the hex is less than six characters), all of the inputs disappear! This has the effect of deleting values that the user has already input. E.g. when the user types a valid 6-character hex value, and then presses the delete key to correct the last character of the hex, the entire hex value disappears, and needs to be retyped completely. If you watch in the console, you can see that what's occurring. I think it's correct behavior for the rgb inputs to disappear when the hex is invalid, but it clearly hampers the user to erase the value he/she is in the process of typing.

This is clearly happening because of the "double-bind"-- the rgb and hex values are watching their own model, but also each other. There's some serious infinite loop potential here, and it's probably only working at all because the angular docs say the loop only runs 10x to prevent an infinite loop deadlock.

I'm pretty sure I'm doing this wrong way to begin with. Should I try to write a separate directive for the hex input? If so how should I link them all up? Is $watch legit for this kind of use? A working fiddle is most helpful.

Ben
  • 9,132
  • 8
  • 29
  • 45

1 Answers1

5

$watch works well for one way dependency. You want to have something that flip flops dependency based on what the user inputs. For this, use ng-change on the inputs:

http://jsfiddle.net/F545z/1/

<div ng-app>
    <form ng-controller="myCtrl" novalidate>
        R:<input ng-model="redChannel" ng-change="updateHex()" type="number"  min="0" max="255" required></input>
        G:<input ng-model="greenChannel" ng-change="updateHex()" type="number"  min="0" max="255" required></input>
        B:<input ng-model="blueChannel" ng-change="updateHex()" type="number"  min="0" max="255" required></input>
        <br><br>
        hex: #<input ng-model="hexColor" ng-change="updateChannels()" type="text" required></input>
    </form>
</div>
Karen Zilles
  • 7,613
  • 3
  • 32
  • 31