简体   繁体   中英

Two-way Data Binding Between Scopes

I've created 3 directives, an XY area slider, an X slider, and a ColorPicker directive that uses the two other directives.

I've gotten everything working except being able to get them to move together when sharing the same model.

View Plunker

In the above Plunker, you can find the full source and see what I mean about them not sharing the model properly. I'd like for it to be so that when one slider moves, they all move.

The values are updating properly in the 3rd (color-picker) directive, so I believe that's where the fault lies.

ColorPicker Directive:

angular.module('plunker').directive('isColorPicker', IsColorPicker);

IsColorPicker.$inject = [];

function IsColorPicker() {
  'use strict';

  return {
    restrict: 'EA',
    scope: {
      color: '='
    },
    template: [
      '<div class="is-color-picker">',
      '    <div style="background: {{ color.hueHex }}" class="hsv-container">',
      '        <is-xy-field values="xyValues"></is-xy-field>',
      '    </div>',
      '    <div class="hue-container">',
      '        <is-slider max="360" value="hueValue"></is-slider>',
      '    </div>',
      '</div>'
    ].join(''),
    replace: true,
    controller: ['$scope', function($scope) {
      $scope.hueValue = 0;
      $scope.xyValues = {
        x: 100,
        y: 100
      };

      updateColors();

      $scope.$watch('xyValues', function(value) {
        updateColors();
      }, true);

      $scope.$watch('hueValue', function(value) {
        updateColors();
      }, true);

      function updateColors() {
        var hsl = {
          h: parseInt($scope.hueValue),
          s: $scope.xyValues.x / 100,
          v: $scope.xyValues.y / 100
        };

        $scope.color = hsv2rgb(hsl.h, hsl.s, hsl.v);
        $scope.color.hsl = hsl;
        $scope.color.hueHex = hsv2rgb(hsl.h, 1, 1).hex;
      }

      function hsv2rgb(h, s, v) {
        var R, G, B, X, C;
        h = (h % 360) / 60;
        C = v * s;
        X = C * (1 - Math.abs(h % 2 - 1));
        R = G = B = v - C;

        h = ~~h;
        R += [C, X, 0, 0, X, C][h];
        G += [X, C, C, X, 0, 0][h];
        B += [0, 0, X, C, C, X][h];

        var r = R * 255,
          g = G * 255,
          b = B * 255;
        return {
          r: r,
          g: g,
          b: b,
          hex: "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1)
        };
      }
    }],
  }
}

So the problem seems that for each individual colorpicker you create your own isolated hueValue scope. You need from your main controller provide a shared hueValue variable. I did some modifications to your code and will show it below.

HTML

<div class="pickers">
    <is-color-picker color="colorObj" hue-value="colorObj.hsl.h"></is-color-picker>
    <is-color-picker color="colorObj" hue-value="colorObj.hsl.h" class="is-color-picker2"></is-color-picker>
    <is-color-picker color="colorObj" hue-value="colorObj.hsl.h" class="is-color-picker3"></is-color-picker>
</div>

I've added the hue-value attribute which will be synchronized across all color-pickers.

isColorPicker.js

scope: {
  color: '=',
  hueValue: "=" //This line is new, this is the hue-value from the html
}

Here is a forked plunker

Update

plunker

Since the goal was to eliminate the extra hue-value in the HTML code it now looks like this:

HTML

<body ng-controller="MainCtrl">
  <div class="pickers">
    <is-color-picker color="colorObj"></is-color-picker>
    <is-color-picker color="colorObj" class="is-color-picker2"></is-color-picker>
    <is-color-picker color="colorObj" class="is-color-picker3"></is-color-picker>
  </div>

   Hue Value: {{ colorObj.hueValue }} <br>
   Hue Color:
   <div style="background: {{ colorObj.hueHex }}" class="hue-preview"></div><br>
   Selected Color: <div style="background: {{ colorObj.hex }}" class="hue-preview"></div>
</body>

All colorObj now contains an extra variable called hueValue which reflects what hue we have set in one of the three color-pickers.

isColorPicker.js

template: [
  '<div class="is-color-picker">',
  '    <div style="background: {{ color.hueHex }}" class="hsv-container">',
  '        <is-xy-field values="xyValues"></is-xy-field>',
  '    </div>',
  '    <div class="hue-container">',
  '        <is-slider max="360" value="color.hueValue"></is-slider>',
  '    </div>',
  '</div>'
].join(''),

The important change here is that it now says color.hueValue and not hueValue

Further, the controller initialization is changed to:

$scope.xyValues = {
    x: 100,
    y: 100
};
$scope.color = hsv2rgb(0, 1, 1); //This creates the color object so we can assign the needed color.hueValue variable
$scope.color.hueValue = 0; 

The $scope.$watch has changed to:

$scope.$watch('color.hueValue', function(value) {
    updateColors();
}, true);

Finally the function updateColors is changed to this

function updateColors() {
  var  hsl = {
      h:  parseInt($scope.color.hueValue),
      s:  $scope.xyValues.x / 100,
      v:  $scope.xyValues.y / 100
  };

  $scope.color = hsv2rgb(hsl.h, hsl.s, hsl.v);
  $scope.color.hsl = hsl;
  $scope.color.hueValue = hsl.h;
  $scope.color.hueHex = hsv2rgb(hsl.h, 1, 1).hex;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM