首先在ngRepeat中为ngModel分配自定义指令

时间:2017-07-10 09:51:40

标签: javascript angularjs angularjs-directive angular-ngmodel

我已经创建了一个自定义指令作为<select>元素的替代品(我们可能有数百万条结果,所以我将其拆分为页面)。

其中一个用途是为动态创建的对象赋值,当将值赋值给该对象的第一个项时,它工作得很好,但是当我尝试分配第二个或更多时,它只会覆盖第一个ngModel

由于该项目是为了工作而保密,因此我将添加最低限度的代码,除非您需要查看更多代码(当然它们都将被编辑)。

感谢您的帮助

ks-select-modal指令:

app.controller('SelectModalCtrl', function($scope)
{
});
app.directive('ksSelectModal', function($parse)
{
    var rtn =
    {
        restrict: 'E',
        templateUrl: "/scripts/directives/ksSelectModal/ksSelectModalPrivate.html",
        scope: {
            mdNoFloat: '@',
            ksPlaceholder: '@',
            ksArray: '=',
            ksDisplay: '=',
            ngModel: '=',
            ksTitle: '=',
            ksNoMargin: '@',
            ksInclude: '@',
            ksInit: '=',
            ksId: '@',
            ksResults: '@',
            ksChangePage: '&',
            ksRequired: '@'
        },
        require: 'ngModel',
        controller: function($scope)
        {
            if ($scope.selectModel === undefined)
            {
                $scope.selectModal = {
                    inScope: true
                };
            }
        },
        link: function($scope, element, attrs, ngModel)
        {
            var model = $parse(attrs.ngModel);

            console.log(model);

            $scope.$watch('ngModel', function(newValue, oldValue)
            {
                console.log(newValue);
            });

            if ($scope.ksRequired)
            {
                ngModel.$validators.ksRequired = function (modelValue, viewValue)
                {
                    console.log('test');
                    if (viewValue)
                    {
                        ngModel.$setValidity('ksRequired', true);
                    }
                    else
                    {
                        ngModel.$setValidity('ksRequired', false);
                    }

                    console.log(ngModel.$valid);

                    return viewValue;
                };
            }

        }
    };

    return rtn;
});
app.directive('ksSelectModalPrivate', function($parse, $q, $timeout, $compile, $http, $mdDialog, $document)
{
    var rtn =
    {
        restrict: 'E',
        templateUrl: "/scripts/directives/ksSelectModal/ksSelectModal.html",
        scope: {
            mdNoFloat: '=',
            ngModel: '=',
            ksResults: '=',
            ksPlaceholder: '=',
            ksArray: '=',
            ksDisplay: '=',
            ksTitle: '=',
            ksNoMargin: '=',
            ksInclude: '=',
            ksId: '=',
            ksChangePage: '=',
            ksRequired: '='
        },
        require: 'ngModel',
        link: function($scope, element, attrs, ngModel)
        {
            var model = $parse(attrs.ngModel);

            $scope.$watch('filter', function(newValue, oldValue)
            {
                if ($scope.prevSearch)
                {
                    $timeout.cancel($scope.prevSearch);
                }

                $scope.prevSearch = $timeout(function()
                {
                    $scope.FirstPage();
                }, 1000);
            });

            $scope.Open = function(ev)
            {
                $scope.$parent.selectModal.Open(ev);
            };

            $scope.OnSelect = function(value)
            {
                $scope.$parent.selectModal.OnSelect(value);
            };

            $scope.FirstPage = function()
            {
                angular.element('#' + $scope.ksId + ' .loading').css('display', 'block');

                $scope.$parent.selectModal.page = 1;

                $scope.ksChangePage({
                    page: $scope.$parent.selectModal.page,
                    results: $scope.ksResults,
                    filter: $scope.filter
                }).then(function()
                {
                    angular.element('#' + $scope.ksId + ' .loading').css('display', 'none');
                });
            }

            $scope.NextPage = function()
            {
                angular.element('#' + $scope.ksId + ' .loading').css('display', 'block');

                $scope.$parent.selectModal.page++;

                $scope.ksChangePage({
                    page: $scope.$parent.selectModal.page,
                    results: $scope.ksResults,
                    filter: $scope.filter
                }).then(function()
                {
                    angular.element('#' + $scope.ksId + ' .loading').css('display', 'none');
                });
            }

            $scope.PrevPage = function()
            {
                angular.element('#' + $scope.ksId + ' .loading').css('display', 'block');

                $scope.$parent.selectModal.page--;

                $scope.ksChangePage({
                    page: $scope.$parent.selectModal.page,
                    results: $scope.ksResults,
                    filter: $scope.filter
                }).then(function()
                {
                    angular.element('#' + $scope.ksId + ' .loading').css('display', 'none');
                });
            }

            $scope.$parent.selectModal = {
                isOpen: false,
                element: element,
                page: 1,
                OnSelect: function(value)
                {
                    $scope.$parent.selectModal.isOpen = false;

                    console.log($scope.ngModel);
                    ngModel.$viewModel = value;

                    model.assign($scope, value);

                    console.log(ngModel.$viewModel);

                    $mdDialog.hide();

                    $scope.$watch(ngModel.$viewModel, function(newValue, oldValue)
                    {
                        if (newValue == null)
                        {
                            angular.element($scope.$parent.selectModal.element).children('md-input-container').children('label').css({
                                display: 'block'
                            });
                        }
                    });

                    if ($scope.mdNoFloat !== undefined)
                    {
                        angular.element($scope.$parent.selectModal.element).children('md-input-container').children('label').css({
                            display: 'none'
                        });
                    }
                    else
                    {
                        angular.element($scope.$parent.selectModal.element).children('md-input-container').addClass('md-input-has-value');
                        angular.element($scope.$parent.selectModal.element).children('md-input-container').removeClass('md-input-focused');
                    }
                },
                Open: function(ev)
                {
                    $scope.$parent.selectModal.isOpen = true;

                    if ($scope.mdNoFloat !== undefined)
                    {
                    }
                    else
                    {
                        angular.element($scope.$parent.selectModal.element).children('md-input-container').addClass('md-input-focused');
                    }

                    console.log($scope.ksId);

                    $mdDialog.show({
                        contentElement: '#' + $scope.ksId,
                        parent: angular.element(document.body),
                        targetEvent: ev,
                        clickOutsideToClose: true
                    }).finally(function()
                    {
                        $scope.$parent.selectModal.isOpen = false;
                    });
                }
            };

            var elemClickHandler = function(e)
            {
                e.stopPropagation();
            };

            var docClickHandler = function()
            {
                if (!$scope.$parent.selectModal.isOpen)
                {
                    angular.element($scope.$parent.selectModal.element).children('md-input-container').removeClass('md-input-focused');
                }
            };

            element.on('click', elemClickHandler);
            $document.on('click', docClickHandler);
        }
    };

    return rtn;
});

ksSelectModal.html

<style>
    ks-select-modal .md-button:hover:not([disabled])
    {
        background-color: transparent;
    }
    ks-select-modal .md-button:hover:not([disabled]) .md-list-item-inner
    {
        color:rgba(0, 0, 0, 0.87) !important;
    }
    ks-select-modal md-list-item
    {
        border-bottom:1px solid rgba(0,0,0,0.12);
    }
    ks-select-modal .md-input-focused md-list-item
    {
        border-bottom: 2px solid rgb(63,81,181);
    }
</style>
<md-input-container ng-style="{ 'margin': (ksNoMargin ? '0px' : 'inherit') }">
    <label style="bottom:77%; padding-left: 5px;">{{ ksPlaceholder }}</label>
    <md-list>
        <md-list-item md-no-ink ng-click="Open($event)">
            <span style="margin-left: -15px;" ng-bind="ksDisplay"></span>
            <md-icon class="md-secondary" md-svg-src="/v1/images/icons/ic_arrow_drop_down_black_24px.svg" style="margin-right: -20px;"></md-icon>
        </md-list-item>
    </md-list>
</md-input-container>
<div style="display: none" ng-init="FirstPage()">
    <div class="md-dialog-container" id="{{ksId}}">
        <md-dialog layout-padding>
            <p>{{ ksTitle }}</p>
            <div>
                <md-button class="md-primary md-raised" ng-click="PrevPage()" ng-if="$parent.selectModal.page > 1">
                    <i class="mdi mdi-chevron-left"></i>
                </md-button>
                <md-button class="md-primary md-raised md-secondary" ng-click="NextPage()">
                    <i class="mdi mdi-chevron-right"></i>
                </md-button>
                <md-input-container>
                    <label>Filter</label>
                    <input type="text" ng-model="filter" />
                </md-input-container>
                <md-progress-circular style="position:absolute;top:30px;right:30px;" md-mode="indeterminate" class="md-secondary loading"></md-progress-circular>
            </div>
            <ng-include src="ksInclude"></ng-include>
        </md-dialog>
    </div>
</div>

ksSelectModalPrivate.html

<ks-select-modal-private md-no-float="mdNoFloat"
                         ng-model="ngModel"
                         ks-placeholder="ksPlaceholder"
                         ks-array="ksArray"
                         ks-display="ksDisplay"
                         ks-title="ksTitle"
                         ks-no-margin="ksNoMargin"
                         ks-id="ksId"
                         ks-required="ksRequired"
                         ks-change-page="ksChangePage"
                         ks-results="ksResults"
                         ks-include="ksInclude">
</ks-select-modal-private>

这是指令与ngRepeat一起使用的地方:

<md-list flex="100" flex-sm="100" flex-xs="100">
    <md-subheader class="md-no-sticky">Properties</md-subheader>
    <md-list-item ng-repeat="item in selectedProperties" id="property-list">
        <p>{{ item.DisplayText}}</p>
        <md-content class="md-secondary">
            <table>
                <tr>
                    <td align="right" style="width:100%;">
                        <ks-select-modal style="width:100%"
                                         ks-id="selectDataType"
                                         ks-title="'Select Data Type'"
                                         ks-array="dataTypes"
                                         ks-placeholder="Select Data Type"
                                         ng-model="item.DataType"
                                         ks-display="item.DataType._DataType"
                                         ks-results="21"
                                         ks-required="true"
                                         ks-change-page="GetDataTypes(page, results, filter)"
                                         ks-include="/v1/views/pages/site/modals/select-data-type.html">

                        </ks-select-modal>
                        <div ng-messages="item.DataType.$error">
                            <div ng-message="ksRequired">required</div>
                        </div>
                    </td>
                    <td align="right">
                        <md-button class="md-icon-button" aria-label="Remove" ng-click="RemoveProperty(item.Id)">
                            <md-icon md-svg-icon="images/icons/ic_delete_black_24px.svg"></md-icon>
                        </md-button>
                    </td>
                </tr>
            </table>


        </md-content>
    </md-list-item>
    <md-divider></md-divider>
        <ks-select-modal style="width:100%"
                         ks-title="'Select Property'"
                         ks-array="propertyConcepts"
                         ks-id="selectProperty"
                         md-no-float
                         ks-no-margin
                         ks-placeholder="Select Property"
                         ng-model="lastProperty"
                         ks-display="lastProperty.DisplayText"
                         ks-results="21"
                         ks-change-page="GetProperties(page, results, filter)"
                         ks-include="/v1/views/pages/site/modals/select-concept.html"></ks-select-modal>
</md-list>

select-data-type.html

<md-list>
    <md-list-item ng-repeat="dataType in ksArray" style="float:left; width:30%;min-width:300px;">
        {{ dataType._DataType }}
        <md-button class="md-secondary" ng-click="OnSelect(dataType)">Select</md-button>
    </md-list-item>
</md-list>

唯一需要的其他信息是$watch范围变量上有lastProperty,它将值添加到selectedProperties数组中。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

我已经解决了这个问题。

传递到ksId的ID对于ngRepeat创建的所有元素都是相同的。通过更改ksId值以将{{$index}}添加到其末尾可以解决问题。