How can I prevent jQuery-UI buttonsets from breaking AngularJS bindings?

In the code below, the fact that I am calling $(".test").buttonset(); is breaking updating of {{ item.value() }}. I assume it has something to do with jQuery UI rewriting the 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>

Here is a jsFiddle version: http://jsfiddle.net/vhLXW/

Dom Manipulation in the Controller is not a good idea. WHat you could do is create a simple directive which will take care of doing the buttonset() job for you. It would look something like

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

And in your html, you could do

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

Now your code has no dependancy on the presence of class="test" in your html.

What is happening in your situation is that the JQuery UI is transforming the DOM. It is hiding your radio buttons and putting in other html Elements ( restyling the radio group ). When this new widget is clicked the JQuery UI code propagates that click to the correspoding Radio Button.

If JQuery UI exposed an event or something similiar, then we could have hooked into that and from Angular you could have called $scope.$apply(); . But, unfortunately it doesnt seem be to the case ( unless I am mistaken ).

If you really need the look of JQuery UI you could write your own code ( copy paste the specific piece of HTML after JQuery UI manipulates the DOM ). Use the styling from JQuery UI and write your own logic. Angular makes it extremely easy to write your own logic.

Let jQuery UI modify the DOM first, then let AngularJS do its DOM manipulation. This way, Angular will bind to the modified DOM elements. I put your JavaScript at the bottom of the page to get it to work without the need for a timeout:

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

UPDATE: as @Chas.Owens pointed out, this does not work. Although data binding works correctly, the UI is broken. If seems that if jQuery UI modifies the DOM first (as shown above), AngularJS data binding works, but it somehow breaks the UI. If AngularJS modifies the DOM first (the original problem), AngularJS data binding doesn't work (likely because buttonset adds an additional <span> around the label's text), but the UI works.