【问题标题】:Changes in jQuery UI not reflected on Angular modelsjQuery UI 的变化没有反映在 Angular 模型上
【发布时间】:2013-06-23 19:20:29
【问题描述】:

我有一个在指令中的表格。它包含 2 个选择下拉菜单(jQuery 样式)和一个 jQuery UI 滑块,所以它们都是一致的主题。

Dropdown 1 在生成时填充,就像它们一样简单。 当 Dropdown 1 的值更改时,Dropdown 2 会被填充。发生这种情况是因为下拉菜单 1 附加了 ng-change="refreshModels()"。这就像一个魅力。

但是,滑块的问题更大。 为了获得滑块的值,我需要一个隐藏的输入字段,在滑块位置的每次更改时都会填充 $.val() 。值会正确更新,甚至会触发 change 事件(当我将 onchange="console.log('I changed')" 放到隐藏字段中时,所有内容都会被很好地记录下来)。

但是,附加到同一个隐藏字段的 ng-model 永远不会更新。与 onchange 不同,Ng-change 永远不会触发。

所以我asked around 并尝试在 jQuery 滑块的幻灯片处理程序中执行此操作:

angular.element($(this)).scope().$apply(); 

但没有骰子。什么都没发生。尝试调用我知道该指令中存在的模型,如下所示:

angular.element($(this)).scope().model_that_definitely_exists; 

产生未定义的结果。尝试访问指令的父控制器中的模型也会产生 undefined。

为什么除了直接用户在字段上输入之外的方式进行 Angular 注册更改如此困难?我做错了什么?

附:我尝试将 ng-mouseup 放在成为滑块的元素上,这很好地调用了刷新方法 - 但忽略了隐藏字段。对 Angular 来说,这些仍然是未定义的,尽管实际上它们是有值的——滑块将它们放在那里。

P.P.S.我还尝试将 $watch 放在我希望在移动滑块后更改的模型上,什么都没有。模型的值永远不会改变,即使字段的 val 确实发生了变化。

P.P.P.S.我刚刚发现了这种可悲的状况。 https://github.com/angular-ui/angular-ui/issues/252如果有人有解决方法,我将不胜感激。

【问题讨论】:

标签: javascript jquery forms jquery-ui angularjs


【解决方案1】:

我最近为 jqueryUiSlider 编写了一个自定义指令。

您可以在 GitHub (https://github.com/jvandemo/CoconutJS/blob/master/src/jquery-ui/directives/ccnutJqueryUiSlider.js) 上查看它,但我会在此处发布以供参考:

angular.module('ccnut.jquery-ui.directives')
    .directive('ccnutJqueryUiSlider', ['ccnut.config', 'logger', function (ccnutConfig, logger) {
        return {
            restrict: 'AC',
            require: 'ngModel',
            link: function (scope, iElement, iAttrs, ngModelController) {

                if (!window.$ || !window.$.fn || !window.$.fn.datepicker) {
                    return logger.warn('ccnutJqueryUiSlider directive skipped: slider function from jQuery UI library not available');
                }

                // Get options
                var options = angular.extend({}, scope.$eval(iAttrs.ccnutJqueryUiSlider));

                // Initialize slider
                iElement.slider(options);

                // Update model on slide event
                iElement.on('slide', function (event, ui) {
                    ngModelController.$setViewValue(ui.value);
                    scope.$apply();
                });

                // Update slider when view needs to be updated
                ngModelController.$render = function () {
                    var value = (ngModelController.$viewValue || 0);
                    iElement.slider('value', value);
                };

            }
        };
    }]);

这里,ngModelController 用于将滑块的值“绑定”到使用ng-model="yourModelName" 分配给指令的模型。

用法简单如下:

<div ng-model="model" ccnut-jquery-ui-slider="{min:1, max:5}"></div>

这将创建一个滑块并将值存储在ng-model 指定的模型中。

更新模型时,滑块也会滑动到新值。

您可以在https://github.com/jvandemo/CoconutJS/blob/master/src/jquery-ui/directives/ccnutJqueryUiSlider.js的源代码的 cmets 中阅读一些额外的文档

希望有帮助!

【讨论】:

  • 您如何将其应用于范围滑块,因为只能绑定一个模型?我尝试过这种方式,但结果并不理想:hastebin.com/qotafaduwi.html
  • 我删除了 ng-model 和其他一些依赖项,并使其范围兼容。感谢您朝着正确的方向前进! github.com/Swader/ngdirectives
  • 看起来很棒,很高兴能帮上忙!
【解决方案2】:

不确定这是否是大量的代码,但我倾向于认为一个不错的选择是使用一个简单的指令来创建/连接 jQueryUI 滑块。下面制作的简单指令在指令作用域上的“值”属性和控制器作用域上的“值”属性之间建立了双向绑定。指令的模板只是在指令的链接功能期间变成滑块的 div,它还为“幻灯片”事件设置了一个侦听器并将值复制到范围。还设置了 $watch,以便将来自控制器的更改推送到滑块的状态。

您可以通过此 JSBin 实时查看以下示例(与我上面评论的不同):http://jsbin.com/ejojad/1/edit

HTML:

<!DOCTYPE html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
  <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/smoothness/jquery-ui.min.css" rel="stylesheet" type="text/css" />
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
  <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
  <meta charset=utf-8 />
  <title>JS Bin</title>
</head>
<body>
  <div ng-app="myApp" ng-controller="Ctrl">
    <input type="text" ng-model="value"/>
    <jqui-slider value="value"></jqui-slider>
  </div>
</body>
</html> 

JavaScript:

function Ctrl($scope) {
  $scope.value = 0;
}

function jQuiSliderDirective() {
  return {
    restrict: 'E',
    scope: {
      value: '=value',
    },
    template: '<div></div>',
    replace: true,
    link: function($scope, elem, attrs) {
      var slider = $(elem).slider();
      slider.on('slide', function(event, ui) {
        $scope.$apply(function() {
          $scope.value = ui.value;
        });
      });
      $scope.$watch('value', function(val, old) {
        slider.slider('value', val);
      });
    }
  };
}

var myApp = angular.module('myApp', []);
myApp.directive('jquiSlider', jQuiSliderDirective);

【讨论】:

  • 由于某种原因,它从 jQuery 抛出错误“方法 addClass 未定义”。不过,很好的例子,谢谢 - 我从中学到了很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-07
  • 2018-09-23
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多