【问题标题】:How can I prevent jQuery-UI buttonsets from breaking AngularJS bindings?如何防止 jQuery-UI 按钮集破坏 AngularJS 绑定?
【发布时间】:2012-08-13 13:59:45
【问题描述】:

在下面的代码中,我调用$(".test").buttonset(); 的事实破坏了{{ item.value() }} 的更新。我认为这与 jQuery UI 重写 DOM 有关。

<html ng-app>
    <head>
        <link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/start/jquery-ui.css" type="text/css" rel="Stylesheet" />
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
        <script type="text/javascript">
            function ExampleCtrl($scope, $timeout) {
                $scope.list = [
                    { name: "a", value: 5 },
                    { name: "b", value: 6 },
                    { name: "c", value: 5 },
                    { name: "d", value: 6 }
                ];

                $scope.calc = [
                    [
                        {
                            name: "a, b avg",
                            value: function() { return(($scope.list[0].value + $scope.list[1].value) / 2) }
                        },
                        {
                            name: "c, d avg",
                            value: function() { return(($scope.list[2].value + $scope.list[3].value) / 2) }
                        }
                    ]
                ];

                $timeout(function() {
                    $(".test").buttonset();
                }, 0);
            }
        </script>
    </head>
    <body ng-controller="ExampleCtrl">
        <div class="test" ng-repeat="group in calc">
            <div ng-repeat="item in group">
                <input type="radio" name="a" id="{{item.name}}" />
                <label for="{{item.name}}">{{item.name}}: {{ item.value() }}</label>
            </div>
        </div>

        <ul ng-repeat="item in list">
            <li>{{item.name}}: <input type="number" ng-model="item.value" />
        </ul>
    </body>
</html>

这里是一个 jsFiddle 版本:http://jsfiddle.net/vhLXW/

【问题讨论】:

    标签: javascript jquery-ui angularjs


    【解决方案1】:

    Controller 中的 Dom 操作不是一个好主意。您可以做的是创建一个简单的指令,它将为您完成 buttonset() 工作。它看起来像

    directive('buttonset', function() {
        return function(scope, elm, attrs) {
          elm.buttonset();
        };
      });
    

    在你的 html 中,你可以这样做

    <div class="test" ng-repeat="group in calc" buttonset>
    

    现在您的代码不再依赖于 class="test" 在您的 html 中的存在。

    您的情况是 JQuery UI 正在转换 DOM。它隐藏了您的单选按钮并放入其他 html 元素(重新设置单选组的样式)。单击此新小部件时,JQuery UI 代码将该单击传播到相应的单选按钮。

    如果 JQuery UI 暴露了一个事件或类似的东西,那么我们可以挂钩到那个,从 Angular 你可以调用$scope.$apply();。但是,不幸的是,情况似乎并非如此(除非我弄错了)。

    如果您真的需要 JQuery UI 的外观,您可以编写自己的代码(在 JQuery UI 操作 DOM 后复制粘贴特定的 HTML)。使用 JQuery UI 中的样式并编写自己的逻辑。 Angular 让编写自己的逻辑变得非常容易。

    【讨论】:

    • 这是我目前拥有的 jsFiddle 版本:jsfiddle.net/vhLXW 这是一个 jsFiddle 版本,可以按照我的建议进行操作:jsfiddle.net/vhLXW/1 首先,按钮集有效,但更新无效.在第二个中,按钮集没有被创建,但更新工作。
    • 这是一个使用指令的小提琴,按钮集在其中工作。 jsfiddle.net/ganarajpr/vhLXW/2。就像我在回答中所说的那样,如果您希望它更新,您必须创建自己的按钮集(您可以使用 JQuery UI 设置样式!)。
    【解决方案2】:

    让 jQuery UI 先修改 DOM,然后让 AngularJS 进行 DOM 操作。这样,Angular 将绑定到修改后的 DOM 元素。 我将您的 JavaScript 放在页面底部以使其无需超时即可工作:

    </body>
    <script type="text/javascript">
        $(".test").buttonset()  // allow jQuery UI to manipulate the DOM here, first!
        function ExampleCtrl($scope) {
            $scope.list = [ ... ];
            $scope.calc = [ [...] ];
        }
    </script>
    

    更新:正如@Chas.Owens 指出的那样,这不起作用。尽管数据绑定工作正常,但 UI 已损坏。如果 jQuery UI 首先修改 DOM(如上所示),AngularJS 数据绑定可以工作,但它会以某种方式破坏 UI。如果 AngularJS 先修改 DOM(最初的问题),AngularJS 数据绑定不起作用(可能是因为 buttonset 在标签文本周围添加了一个额外的 ),但 UI 可以工作。

    【讨论】:

    • 虽然丑陋,但这比复制 jQuery UI 已经完成的所有工作更好。
    • 看来我说得太早了,按钮设置不起作用:jsfiddle.net/vhLXW/3
    • 什么浏览器?你的小提琴在 IE8 和 Chrome 21 (21.0.1180.75 m) 中对我有用。当我更改其中一个列表项中的数值时,相应的按钮集 avg 会更新。
    • 更新成功,按钮集坏了。单击按钮集中的一个按钮应使其变为绿色(而另一个返回蓝色)。这是在 Chrome 21 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    相关资源
    最近更新 更多