Pregunta

I am trying to show an array of data with ng-repeat directive of AngularJS. This html code works under the same controller and have the same scope with constants variable updated async:

 <div class="popup3" id="constant_insert">
        <h2>Insert constant</h2>
        <select id="constants" ng-model="clonedModel.category" ng-options="c.name for c     in constants"></select>
        <div ng-repeat="c in constants">
            <input type="radio" ng-model="model.selected" ng-value="c"/> {{ c.name }}     <br/>
        </div>
        <div style="clear: both; height: 20px;"></div>
        <div id="confirm" class="save_button">Insert</div>
        <div id="cancel" class="save_button">Cancel</div>
    </div>

ng-options works with my data and shows the content of the constants but ng-repeat is not.

The resulting HTML is this:

<div class="popup3 ng-scope visible" id="constant_insert">
        <h2>Insert constant</h2>
        <select id="categories" ng-model="clonedModel.category" ng-options="c.name for     c in constants" class="ng-pristine ng-valid"><option value="?" selected="selected">    </option><option value="0">aa</option><option value="1">ee</option></select>
        <!-- ngRepeat: c in constants -->
        <div style="clear: both; height: 20px;"></div>
        <div id="confirm" class="save_button">Insert</div>
        <div id="cancel" class="save_button">Cancel</div>
    </div>

Yes, data is from async call, and this html generated from template by transclude directive but as far as ng-options shows the data, all this usuall scope.$apply stuff is already done and it seems to me its unrelevant to the problem, so I omit all these code. The question is - why ng-repeat cannot work with the data ng-options capable to work with? Whats so special about ng-repeat? Is there any gotchas I need to know about? Ofc if I make a simple controller with this html template then both of the directives will work. But I am trying to find a bug and it hides somewhere in the diffrences of how these directives handles the data.

Thanx!

PS: the directive:

.directive('modalDialog', function ($compile, $http, Notification) {
        return {
            restrict: 'A',
            transclude: true,
            replace: false,
            scope: {
                confirm: '&',
                cancel: '&',
                init: '&',
                model: '='
            },
            link: function postLink(scope, element, attrs) {
                app.log('modal link');
                //clone model
                scope.clonedModel = {};
                scope.isNew = attrs.creating ? true : false;
                app._clone(scope.model, scope.clonedModel, false);
                var modal = $('<div class="overlay"></div>');
                modal.attr('id', scope.$id);
                var dialog;
                var _dialog;
                if (attrs.templateId) {
                    dialog = $('#' + attrs.templateId).clone();
                    bind();
                } else if (attrs.partialName) {
                    $http.get('partials/' + attrs.partialName + '.html', {cache: true}).then(function (response) {
                        modal.html(response.data);
                        dialog = modal.children();
                        bind();
                    });
                }
                function closeDialog(button) {
                    app.log('modal close');
                    button.off('click');
                    modal.removeClass('visible');
                    _dialog.removeClass('visible');
                    scope.$apply(function () {
                        scope.cancel()
                    });
                }
                function bindConfirm(button) {
                    app.log('bind confirm');
                    button.on('click', function () {
                        app.log('clear bind confirm');
                        button.off('click');
                        app._clone(scope.clonedModel, scope.model, false);
                        scope.confirm({model: scope.model, isNew: scope.isNew}).then(function () {
                            app.log('dialog scope confirm');
                            //succeeded
                            modal.removeClass('visible');
                            _dialog.removeClass('visible');
                        }, function (response) {
                            //failed
                            var errorMessage = response.data ? response.data : "Unknown error, status code:" + response.status;
                            Notification.notify('Error', errorMessage, 4000);
                        });
                    });
                }
                function bind() {
                    app.log('modal bind');
                    scope.init({model: scope.clonedModel, localScope: scope});
                    _dialog = $compile(dialog)(scope);
                    var button = _dialog.find('#confirm');
                    $('input, textarea', _dialog).first().trigger('focus');
                    $(_dialog).keyup(function (event) {    //close on Esc
//                        app.log("Key pressed: ");
//                        app.log(event);
                        if (event.which == 27) closeDialog(button);
                    });
                    _dialog.find('#cancel').on('click', function () {
                        closeDialog(button);
                    });
                    element.on('click', function () {
                        app.log('modal element click');
                        bindConfirm(button);
                        //copy model into scope local var
                        scope.clonedModel = {};
                        scope.$apply(function(scope){
                            app._clone(scope.model, scope.clonedModel, false);
                            scope.init({model: scope.clonedModel, localScope: scope});
                        });
                        $(modal).appendTo('body');
                        $(_dialog).appendTo('body');
                        modal.addClass('visible');
                        _dialog.addClass('visible');
                    });
                    scope.$on('$destroy', function () {
                        modal.remove();
                        dialog.remove();
                    });
                }
            }
        }
    })

this is how it is called from html:

<div id="insert_constant" class="green_button small_button" template-id="constant_insert" style="float: left; position: relative;" model="const" confirm="onConstInsert(model, template)" init="initConstantDialog(model, localScope)" modal-dialog ng-transclude>Constants</div>

and this is init function from scope:

$scope.initConstantDialog = function (model, localScope) {
        localScope.constants = $scope.constants;
        app.log("init constants dialog");
        app.log(model);
        app.log(localScope);
    }

constants contains this:

[{"id":8,"name":"aa","oldName":"aa","value":"aa"},{"id":9,"name":"ee","oldName":"ee","value":"ee"}]

AngularJS v1.2.10

¿Fue útil?

Solución

After some investigation I found the root of the problem here.

The problem was in the HTML template for the directive, which was stored as a hidden DIV element in the parent's HTML. So, when parent controller was loaded, ng-repeat directive in this DIV was compiled and linked with parent's scope and resulting html of this DIV dynamically updated to the <!-- ngRepeat: c in constants -->. Later, when I tried to take this DIV, compile it and use as template, it already was unusable as template.

So the fix is to move template for this directive in the separate HTML file.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top