jQuery UI自动完成功能不会更新ngModel

时间:2018-12-17 13:56:22

标签: javascript jquery angularjs

我正在尝试使用自动完成的jQuery UI将值插入angularjs形式。问题是,当我使用$ http发送数据时,来自自动完成输入的值不会更新ng-model! 我读了一些有关$ scope.apply()的使用的帖子,但是我不知道如何使用它以及在哪里使用! 这是自动完成的jQuery代码:

$(document).ready(function(){
        $("#tags").autocomplete({
             source: '/contabilita/include/autocomplete.asp',
             minChars: 3,
             autoFill: true,
             mustMatch:false,
             cacheLength: 1,
             select: function(event, ui) {
                event.preventDefault();
                $("#tags").val(ui.item.label);
                $("#selected-tags").val(ui.item.label);
                $("#PIVA").val(ui.item.piva);
                $("#CFISCA").val(ui.item.cf);
                $("#CAP").val(ui.item.cap);
                $("#CITY").val(ui.item.city);
                $("#INDIRIZZO").val(ui.item.indi).trigger('change');
                $("#INDIRIZZO").trigger('input');
                $("#PR").val(ui.item.pr).closest('.select-wrapper')
                .find('li').removeClass("active").closest('.select-wrapper')
                .find('.select-dropdown').val(ui.item.pr)
                .find('span:contains(' + ui.item.pr + ')')
                .parent().addClass('selected active');
                $("#PR").select();
            },
        });

这是html:

    <div class="row">
        <div class="col s1">
          <label>N°:
            <input type="text" ng-model="reg.NUMERO">
          </label>
        </div>
        <div class="col s5">
          <label>Intestazione:
            <input ng-model="reg.INTESTAZIONE" id="tags" type="text">
          </label>
        </div>
<div class="row">
        <div class="col s4">
          <label>Indirizzo:
            <input ng-model="reg.INDIRIZZO" id="INDIRIZZO" type="text" ng-model-options="{updateOn: 'change input'}">
          </label>
        </div>
        <div class="col s3">
          <label>Città:
            <input ng-model="reg.CITY" id="CITY" type="text">
          </label>
        </div>
        <div class="col s3">
          <label>CAP:
            <input ng-model="reg.CAP" id="CAP" type="text">
          </label>
        </div>

这是角度控制器:

    .controller('gestFat', function($scope,$http,$location,$rootScope) {
    $scope.reg = {};
    $scope.reg.GIORNO = $rootScope.today;
    $scope.reg.RF = "RF01";
    $scope.reg.T_IVA = "10";
    console.log("cerco la fattura");
    var com = $location.search().COM_ID;


    $scope.stampaFat = function(){
            $http.post('/contabilita/include/insert_fattura.php', $scope.reg)
            .success(function(data){
                M.toast({html:'Intervento inserito...'+data, inDuration:1500});
                })
            .error(function(status){alert("Errore di connessione!" + status)});

    };
})

解决方案:

这是最终解决方案

.directive('ngautocomplete', function () {
return function link(scope, element, attributes) {
    element.autocomplete({
        source: '/contabilita/include/autocomplete.asp',
         minChars: 3,
         autoFill: true,
         mustMatch:false,
         cacheLength: 1,
         select: function(event, ui) {
            event.preventDefault();
                $("#tags").val(ui.item.label);
                $("#PIVA").val(ui.item.piva).trigger('input');;
                $("#CFISCA").val(ui.item.cf).trigger('input');;
                $("#CAP").val(ui.item.cap).trigger('input');;
                $("#CD").val(ui.item.cd).trigger('input');;
                $("#PEC").val(ui.item.pec).trigger('input');;
                $("#CITY").val(ui.item.city).trigger('input');;
                $("#INDIRIZZO").val(ui.item.indi).trigger('input');
                $("#NAZIONE").val(ui.item.nazione).closest('.select-wrapper').find('li').removeClass("active").closest('.select-wrapper').find('.select-dropdown').val(ui.item.nazione).find('span:contains(' + ui.item.nazione + ')').parent().addClass('selected active');
                $("#NAZIONE").select().trigger('change');;
                $("#PR").val(ui.item.pr).closest('.select-wrapper').find('li').removeClass("active").closest('.select-wrapper').find('.select-dropdown').val(ui.item.pr).find('span:contains(' + ui.item.pr + ')').parent().addClass('selected active');
                $("#PR").select().trigger('change');;
            }
            });
};

})

3 个答案:

答案 0 :(得分:0)

AngularJS有一个“摘要循环”,大致类似于浏览器的事件循环。每个周期,Angular决定需要更新DOM的哪些部分。您的jQuery代码不会以任何方式引用Angular,因此无法知道您的自动填充数据已更改,或者屏幕需要更新。

解决此问题的一般方法是在中编写基于Angular的函数(如组件或指令)的jQuery代码。关于如何执行此操作的教程很多。这也是$scope.$apply()出现的原因,这是告诉Angular需要进行更新的另一种方式。

我建议您创建一个directive。在该指令中,您将引用当前元素的jQuery封装版本,并且可以在其上调用自动完成功能。然后在#tags元素中使用指令。

我从一个旧项目中提取了这个。这有点过时了,但是应该可以证明这个想法。请参考那些有角度的文档以获取真正的交易。

myApp.directive('autocomplete', function () {
    return function link(scope, element, attributes) {
        element.autocomplete({/* options here */});
    };
});

然后,在您的html中:

<div id="tags" autocomplete></div>

答案 1 :(得分:0)

您应该将自动完成功能包装在指令中,因为我看到它对angular应用程序之外的ui进行了许多更改,并且我认为许多更改都会影响angular生成的html。

    angular.directive(‘gest-fat-autocomplete’, function() {
        return {
            require: 'ngModel',
            controller: function($http, $location, $rootScope) {
                this.reg = {};
                this.reg.GIORNO = $rootScope.today;
                this.reg.RF = "RF01";
                this.reg.T_IVA = "10";
                console.log("cerco la fattura");
                var com = $location.search().COM_ID;


                this.stampaFat = function() {
                    $http.post('/contabilita/include/insert_fattura.php', this.reg)
                        .success(function(data) {
                            M.toast({
                                html: 'Intervento inserito...' + data,
                                inDuration: 1500
                            });
                        })
                        .error(function(status) {
                            alert("Errore di connessione!" + status)
                        });

                };
            }

            link: function(scope, element, attr, ctrl) {
                element.autocomplete({
                        source: '/contabilita/include/autocomplete.asp',
                        minChars: 3,
                        autoFill: true,
                        mustMatch: false,
                        cacheLength: 1,
                        select: function(event, ui) {
                            event.preventDefault();
                            scope.$applyAsync(function() {
                                // Update your model here
                                // use ctrl.reg to access this.reg in the controller
                            });
                        },


                    }
                };
            })

您仍然需要向指令添加模板。我没有添加它,因为我不清楚您的应用的HTML。 您也可以在模板中访问控制器实例,因此无需在控制器内部使用$ scope

答案 2 :(得分:0)

要将外部库与AngularJS ng-model集成,请使用自定义指令:

app.directive("xngAutocomplete", function() {
     return {
         require: "ngModel",
         link: postLink,
     };
     function postLink(scope,elem,attrs,ngModel) {
         ̶$̶(̶d̶o̶c̶u̶m̶e̶n̶t̶)̶.̶r̶e̶a̶d̶y̶(̶f̶u̶n̶c̶t̶i̶o̶n̶(̶)̶{̶ ̶$̶(̶"̶#̶t̶a̶g̶s̶"̶)̶.̶a̶u̶t̶o̶c̶o̶m̶p̶l̶e̶t̶e̶(̶{̶
         elem.autocomplete({
             source: '/contabilita/include/autocomplete.asp',
             minChars: 3,
             autoFill: true,
             mustMatch:false,
             cacheLength: 1,
             select: function(event, ui) {
                event.preventDefault();
                ̶$̶(̶"̶#̶t̶a̶g̶s̶"̶)̶.̶v̶a̶l̶(̶u̶i̶.̶i̶t̶e̶m̶.̶l̶a̶b̶e̶l̶)̶;̶
                ngModel.$setViewValue(ui.item.label);
            }
         });
     }
})

用法:

<input xng-autocomplete ng-model="reg.INTESTAZIONE" id="tags" type="text">

指令将代码注入具有xng-autocomplete属性的元素中。该伪指令将jQuery元素作为postLink函数的第二个参数公开给代码。

有关更多信息,请参见