【问题标题】:Change model observable inside custom handler更改自定义处理程序中可观察的模型
【发布时间】:2017-05-26 09:22:34
【问题描述】:

我编写了以下自定义绑定处理程序,它显示了一个 jquery-ui 自动完成列表。 After selecting the element I want to change the given observable value which is given by options.value but there is no change when the select function enters.

ko.bindingHandlers.autocomplete = {
    init : function(element, valueAccessor, allBindings, viewModel, bindingContext) {

        var options = ko.unwrap(valueAccessor());               

        $(element).autocomplete(
                {
                    minLength : 2,
                    autoFocus : true,
                    source : function(request, response) {
                        $.ajax({
                            url : options.source,
                            data : {
                                term : request.term
                            },
                            dataType : "json",
                            type : "GET",
                            success : function(data) {
                                response(data);
                            }
                        });
                    },
                    select : function(event, ui) {
                        var selectedItem = ui.item;
                        options.value(selectedItem.name);
                    }
                });
    }
};

<input data-bind="autocomplete: { 
    value: myView().parent_name,
    source: '/data/autocomplete'
}" 
type="text" class="form-control">

编辑 1

我尝试了评论中的绑定,但仍有问题。

model.autocomplete = function(searchTerm, callback){
    $.ajax({
        type : "GET",
        url : "/data/autocomplete",
        data: {term: searchTerm}
    }).done(callback);
};

输入看起来像这样:

    <input data-bind="jqAuto: { 
        value: myView().parent_name,
        source: myView().autocomplete,
        labelProp: 'name',
        valueProp: 'parent_name'
    }" 
    type="text" class="form-control">

这不会改变 myView().parent_name

编辑 2

我想我现在知道问题所在了。我制作了一个更简单的测试文件,如下所示:

 <!DOCTYPE html>
<html>
<body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<script src="https://rawgit.com/rniemeyer/knockout-jqAutocomplete/master/build/knockout-jqAutocomplete.js"></script>

<h1>Testpage</h1>
<input data-bind="jqAuto : {
        source: sub().autocomplete,
        value: sub().id,
        labelProp: 'name',
        valueProp: 'id'
    }"></input>
<button data-bind="click: sub().output">ok</button>
<button data-bind="click: reset">reset</button>

<script>
function getData() {
    var data = [
        {
            name: "Test1",
            id: 1
        },
        {
            name: "Test2",
            id: 2
        },{
            name: "Test3",
            id: 3
        }       
    ];
    return data;
}

function Submodel() {
    var self = this;

    self.name = ko.observable("");
    self.id = ko.observable(null);

    self.autocomplete = function(searchTerm, callback) {
        callback(getData());
    };

    self.output = function(){
        alert(self.id());
    };
}

function PageModel() {
    var self = this;

    self.sub = ko.observable(new Submodel());

    self.reset = function(){
        self.sub(new Submodel());
    };
}

ko.applyBindings(new PageModel());
</script>

</body>
</html>

有一个子模型在某些时候被清除,但这似乎使绑定无效。直到我按下重置按钮,一切正常。是否有任何解决方案可以在重置后更新绑定。我需要此重置,因为我想在不使用对话框绑定且不手动清理每个变量的情况下使用带有模型的对话框。

【问题讨论】:

  • 确保您没有重新发明轮子:github.com/rniemeyer/knockout-jqAutocomplete
  • 现在您已经尝试了 jqAutocomplete 绑定:向我们展示 myView 视图模型以及 parent_namename 是什么。
  • myModel() 目前唯一定义的是 parent_name = ko.observable(null)。我查看了 jqAuto 的代码,似乎这适用于整个 json 节点,而不仅仅是 parent_name

标签: javascript jquery mvvm knockout.js


【解决方案1】:

根据您提供的(最少)代码以及您在 cmets 中对我的问题的回答,我可能会通过展示一个工作示例来提供帮助。

最重要的要点:

  • 您必须仔细阅读 valuePropinputProplabelProp 之间的区别:它们用于定义您想要在视图模型中存储的内容与您想要的内容向用户展示
  • 确保您的autocomplete 方法返回的数据具有您指定的道具

尝试示例的注意事项:

  • 我没有包含 css,所以很难看
  • 我使用字符串"one""ten" 作为示例数据。输入 oe 或这些词中使用的任何其他字母即可开始。

var Model = function() {
  return {
    parent_name: ko.observable(null),
    autocomplete: function(searchTerm, callback) {
      setTimeout(function() {
        callback(getData().filter(function(v) { 
          return v.name.includes(searchTerm.toLowerCase())
        }));
      }, 200);
    }
  };
};

var vm = {
  myView: ko.observable(new Model()),
  reset: () => vm.myView(new Model())
};

ko.applyBindings(vm);

function getData() {
    return ["one", "two", "three", "four", 
            "five", "six", "seven", "eight", 
            "nine", "ten"]
      .map(str => ({ name: str }));
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script
  src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
  integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
  crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://rawgithub.com/rniemeyer/knockout-jqAutocomplete/master/build/knockout-jqAutocomplete.js"></script>

<p>
  <code>parent_name</code>’s value is: 
  <strong>
    <code data-bind="text: JSON.stringify(myView().parent_name())"></code>  
  </strong>
</p>


<!-- ko with: myView -->
<input data-bind="jqAuto: { 
        value: parent_name,
        source: autocomplete,
        labelProp: 'name',
        valueProp: 'name'
    }" type="text" class="form-control">
<!-- /ko -->

<button data-bind="click: reset">reset</button>

【讨论】:

  • 现在我开始调试jqAutocomplete。在 config.select 回调中有一个对 options.value(ui.item.actual) 的调用,其中 actual 是我选择的值,但未设置 observable。
  • 您必须向我展示更多内容,而不仅仅是说“未设置可观察对象”...我无法重现这一点,因此您可能在其他地方做错了...
  • 我认为问题在于您引用 parent_name 值的方式。当myView() 更改时,对旧parent_name observable 的引用仍然存在。尝试将绑定放在 with: sub 绑定中。
猜你喜欢
  • 1970-01-01
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 2018-06-28
相关资源
最近更新 更多