select2、ng-model 和 angular
Posted
技术标签:
【中文标题】select2、ng-model 和 angular【英文标题】:select2, ng-model and angular 【发布时间】:2015-07-05 00:47:33 【问题描述】:使用jquery-select2(not ui-select)和角度,我正在尝试将值设置为 ng-model。
我尝试过使用 $watch
和 ng-change
,但在使用 select2 选择项目后似乎没有触发。
很遗憾,我使用的是购买的模板,无法使用 angular-ui。
HTML:
<input type="hidden" class="form-control select2remote input-medium"
ng-model="contact.person.id"
value=" contact.person.id "
data-display-value=" contact.person.name "
data-remote-search-url="api_post_person_search"
data-remote-load-url="api_get_person"
ng-change="updatePerson(contact, contact.person)">
客户端控制器:
$scope.updatePerson = function (contact, person)
console.log('ng change');
console.log(contact);
console.log(person);
// not firing
$scope.$watch("client", function ()
console.log($scope.client);
, true); // not firing either
JQuery 集成:
var handleSelect2RemoteSelection = function ()
if ($().select2)
var $elements = $('input[type=hidden].select2remote');
$elements.each(function()
var $this = $(this);
if ($this.data('remote-search-url') && $this.data('remote-load-url'))
$this.select2(
placeholder: "Select",
allowClear: true,
minimumInputLength: 1,
ajax: // instead of writing the function to execute the request we use Select2's convenient helper
url: Routing.generate($this.data('remote-search-url'), '_format': 'json'),
type: 'post',
dataType: 'json',
delay: 250,
data: function (term, page)
return
query: term, // search term
;
,
results: function (data, page) // parse the results into the format expected by Select2.
return
results: $.map(data, function (datum)
var result =
'id': datum.id,
'text': datum.name
;
for (var prop in datum)
if (datum.hasOwnProperty(prop))
result['data-' + prop] = datum[prop];
return result;
)
,
initSelection: function (element, callback)
// the input tag has a value attribute preloaded that points to a preselected movie's id
// this function resolves that id attribute to an object that select2 can render
// using its formatResult renderer - that way the movie name is shown preselected
var id = $(element).val(),
displayValue = $(element).data('display-value');
if (id && id !== "")
if (displayValue && displayValue !== "")
callback('id': $(element).val(), 'text': $(element).data('display-value'));
else
$.ajax(Routing.generate($this.data('remote-load-url'), 'id': id, '_format': 'json'),
dataType: "json"
).done(function (data)
callback('id': data.id, 'text': data.name);
);
,
);
);
;
任何建议将不胜感激! :)
更新
我已经设法将a plunk 放在一起,这似乎同样重现了问题 - 现在看起来好像 ng-watch 和 $watch 事件仅在第一次更改值时才被触发。 尽管如此,在我的代码中(以及在添加进一步的复杂性时,例如从集合中动态添加和删除时),它甚至似乎都没有触发一次。
再次,我们将不胜感激指向正确方向(或真正指向任何方向)的指针!
【问题讨论】:
你能分享一下jquery方面的集成吗?我怀疑您需要做更多的工作来处理 jquery-select2 发出的事件。 如何尝试使用普通的 javascript(或 jQuery)处理程序并使用$scope.$apply
,如 $('.select2remote').on('change', function () var value = $(this).value; $scope.$apply(function () $scope.contact.person.id = value; ); )
来观察输入
@JoeEnzminger 更新
@azium AFAIK $scope 在模块之外对我不可用。我错了吗?
让我们continue this discussion in chat.
【参考方案1】:
您的示例存在许多问题。我不确定我是否能够提供“答案”,但希望以下建议和解释对您有所帮助。
首先,您“混合”了 jQuery 和 Angular。一般来说,这真的行不通。例如:
在 script.js 中,你运行
$(document).ready(function()
var $elements = $('input[type=hidden].select2remote');
$elements.each(function()
//...
);
);
此代码将在 DOM 最初准备就绪时运行一次。它将选择具有 当前在 DOM 中的 select2remote 类的隐藏输入元素,并在它们上初始化 select2 插件。
问题是在这个函数运行之后添加的任何新的 input[type=hidden].select2remote 元素根本不会被初始化。例如,如果您异步加载数据并填充 ng-repeat,就会发生这种情况。
解决方法是将 select2 初始化代码移动到指令中,并将该指令放置在每个输入元素上。删节后,该指令可能如下所示:
.directive('select2', function()
return
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel)
//$this becomes element
element.select2(
//options removed for clarity
);
element.on('change', function()
console.log('on change event');
var val = $(this).value;
scope.$apply(function()
//will cause the ng-model to be updated.
ngModel.setViewValue(val);
);
);
ngModel.$render = function()
//if this is called, the model was changed outside of select, and we need to set the value
//not sure what the select2 api is, but something like:
element.value = ngModel.$viewValue;
);
抱歉,我对 select2 不够熟悉,无法了解用于获取和设置控件当前值的 API。如果您在评论中提供给我,我可以修改示例。
您的标记将更改为:
<input select2 type="hidden" class="form-control select2remote input-medium"
ng-model="contact.person.id"
value=" contact.person.id "
data-display-value=" contact.person.name "
data-remote-search-url="api_post_person_search"
data-remote-load-url="api_get_person"
ng-change="updatePerson(contact, contact.person)">
执行此指令后,您可以删除整个 script.js。
在您的控制器中,您有以下内容:
$('.select2remote').on('change', function ()
console.log('change');
var value = $(this).value;
$scope.$apply(function ()
$scope.contact.person.id = value;
);
);
这里有两个问题:
首先,你在控制器中使用了 jQuery,你真的不应该这样做。 其次,这行代码将在 整个应用程序中的每个元素上触发一个 change 事件,而 当控制器被初始化时在 DOM 中。
由 Angular 添加的元素(即通过 ng-repeat)很可能不会在它们上注册更改监听器,因为它们将在控制器实例化之后添加到 DOM(在下一个消化周期)。
此外,具有更改事件的控制器范围之外的元素将修改控制器 $scope 的状态。再次,解决这个问题的方法是将这个功能移到指令中并依赖 ng-model 功能。
请记住,无论何时离开 Angular 的上下文(即,如果您使用 jQuery 的 $.ajax 功能),您都必须使用 scope.$apply() 重新进入 Angular 的执行上下文。
希望这些建议对您有所帮助。
【讨论】:
这里只是为了完成响应是select2的api:$("#select").select2("val"); //获取值 $("#select").select2("val", "foo"); //设置值所以在这种情况下只需通过 element.select2("val", ngModel.$viewValue) 更改 element.value = ngModel.$viewValue 在我的情况下,选择选项的值与文本(查看值)不同,我必须使用这个:var newViewValue = $('option:selected', this).text();
scope.$apply(function()
ngModel.$setViewValue(newViewValue);
);
以上是关于select2、ng-model 和 angular的主要内容,如果未能解决你的问题,请参考以下文章
Select2 for AngularJS 中的两种方式数据绑定不起作用