0

我有一个可排序的手风琴,在名为“任务”的循环中加载了一个foreach-template循环。ko.observableArray()

在手风琴中,我渲染了 the TaskId、 theTaskName和一个 task Description-all ko.observable()

TaskNameDescription在 input/textarea 元素中呈现。

每当TaskNameDescription更改时,取消选择一个项目,或单击另一个项目,我想调用一个函数来通过 ajax 请求saveEdit(item)将更新的内容发送TaskName到数据库。Description

我需要将TaskId与 Tasks-array 匹配以获取实际的键/值对以发送到saveEdit().

这是 HTML:

<div id="accordion" data-bind="jqAccordion:{},template: {name: 'task-template',foreach: Tasks,afteradd: function(elem){$(elem).trigger('valueChanged');}}"></div> 

<script type="text/html" id="task-template">
     <div data-bind="attr: {'id': 'Task' + TaskId}" class="group">
          <h3><b><span data-bind="text: TaskId"></span>: <input name="TaskName" data-bind="value: TaskName  /></b></h3>
          <p>
             <label for="Description" >Description:</label><textarea name="Description" data-bind="value: Description"></textarea>
          </p>
     </div>
</script>

这是绑定:

ko.bindingHandlers.jqAccordion = {
   init: function(element, valueAccessor) {
       var options = valueAccessor();
       $(element).accordion(options);
       $(element).bind("valueChanged",function(){
          ko.bindingHandlers.jqAccordion.update(element,valueAccessor);
       });
   },
   update: function(element,valueAccessor) {
      var options = valueAccessor();
      $(element).accordion('destroy').accordion(
      {
         // options put here....
         header: "> div > h3"
         , collapsible: true
         , active: false
         , heightStyle: "content"
      })
      .sortable({
              axis: "y",
              handle: "h3",
              stop: function (event, ui) {
                  var items = [];
                  ui.item.siblings().andSelf().each(function () {
                      //compare data('index') and the real index
                      if ($(this).data('index') != $(this).index()) {
                          items.push(this.id);
                      }
                  });
                  // IE doesn't register the blur when sorting
                  // so trigger focusout handlers to remove .ui-state-focus
                  ui.item.children("h3").triggerHandler("focusout");
                  if (items.length) $("#sekvens3").text(items.join(','));
                  ui.item.parent().trigger('stop');
              }
      })
      .on('stop', function () {
              $(this).siblings().andSelf().each(function (i) {
                  $(this).data('index', i);
              });
      })
      .trigger('stop');
   };
};

我的第一个想法是放置线

$root.SelectedTask( ui.options.active );

在我的 viewModel 中定义的 ko.observable.on('click')事件函数中。SelectedTask但是,该.on('click')事件似乎被调用了很多并且它产生了大量的流量。另外,我无法弄清楚将通过ajax函数从Tasks中选择的“项目”发送到数据库的save(item)调用的位置。

非常感谢任何帮助。提前致谢!:)

4

1 回答 1

1

每当更改 TaskName 或 Description 时,取消选择一个项目或单击另一个项目,我想调用函数 saveEdit(item) 以通过 ajax 请求将更新的 TaskName 和 Description 发送到数据库。

这听起来像是您想要做的事情的核心。让我们从任务模型开始

function Task (data) {
    var self = this;
    data = data || {};
    self.id = ko.observable(data.id);
    self.name = ko.observable(data.name);
    self.description = ko.observable(data.description);
}

然后我们需要我们的视图模型:

function ViewModel () {
    var self = this;
    self.tasks = ko.observableArray();
    self.selectedTask = ko.observable();
    self.saveTask = function (task) {
        $.ajax({ ... });// ajax call that sends the changed data to the server
    };

    var taskSubscription = function (newValue) {
        self.saveTask(self.selectedTask());
    };
    var nameSubscription, descriptionSubscription;
    self.selectedTask.subscribe(function (newlySelectedTask) {
        if (newlySelectedTask instanceof Task) {
            nameSubscription = 
                newlySelectedTask.name.subscribe(taskSubscription);
            descriptionSubscription = 
                newlySelectedTask.description.subscribe(taskSubscription);

            self.saveTask(newlySelectedTask);// But why?
        }
    });

    self.selectedTask.subscribe(function (currentlySelectedTask) {
        if (currentlySelectedTask instanceof Task) {
            nameSubscription.dispose();
            descriptionSubscription.dispose();

            self.saveTask(currentlySelectedTask);// But why?
        }
    }, null, 'beforeChange');
}

那么这里发生了什么?其中大部分内容应该是不言自明的,所以我只关注订阅。我们创建了一个taskSubscription函数,因此我们不会在每次self.selectedTask更改时都不断地定义它。

我们有两个订阅者功能。第一个在selectedTask' 值改变后触发,第二个在它改变之前触发。在两者中,我们验证新值是 Task 对象的一个​​实例。在更改后订阅中,我们在namedescription属性上设置了两个订阅。然后我将订阅函数的返回值捕获到两个私有变量中。这些在更改前函数中用于处理这些订阅,以便如果这些任务在当前未选择时被更新,那么我们不会继续触发 saveTask 函数。

我还添加了对observableself.saveTask的每个订阅。selectedTask我问为什么在这里,因为如果我们不知道值是否已更改,为什么要保存它?您可能在这里不必要地发出 ajax 请求。

此外,正如这段代码所展示的,您可以设置这些订阅以在每次值更改时发出 ajax 请求,但最终可能会发出大量请求。更好的选择可能是在您的任务模型中设置可以跟踪它是否“脏”的功能。这意味着它的一个或多个值已更改,需要更新。

function Task (data) {
    var self = this;
    // Make a copy of the data object coming in and use this to save previous values
    self._data = data = $.extend(true, { id: null, name: null, description: null }, data);

    self.id = ko.observable(data.id);
    self.name = ko.observable(data.name);
    self.description = ko.observable(data.description);
    for (var prop in data) {
        if (ko.isSubscribable(self[prop])) {
            self[prop].subscribe(function (oldValue) {
                data[prop] = oldValue;
            }, null, 'beforeChange');
        }
    }
}

Task.prototype.isDirty = function () {
    var self = this;
    for (var prop in self._data) {
        if (ko.isSubscribable(self[prop])) {
            if (self._data[prop] !== self[prop]())
                return true;
        }
    }
    return false;
};

当然你需要一种方法来保存它,或者让它不脏

Task.prototype.save = function () {
    var self = this;
    for (var prop in self._data) {
        if (ko.isSubscribable(self[prop])) {
            self._data[prop] = self[prop]();
        }
    }
};

使用相同的概念,您还可以创建Task.prototype.revert与所做的相反的事情.savename有了这一切,您可以放弃在个人和description属性上设置订阅。我想展示该选项以演示人们可能希望如何.dispose在订阅中使用该方法。但是现在您可以只订阅selectedTaskobservable ('beforeChange') 并查看您要换出的当前选择的任务是否是脏的。如果是,则调用该saveTask函数,完成后,.save在 Task 上调用该函数,使其不再脏。

这可能是我在实现这样的事情时要走的路线。它的美妙之处在于,我没有编写任何与操作视图有关的代码。您可以设置selectedTask任何您认为合适的方式。我要做的是将可观察对象绑定到手风琴内部元素selectedTask上的单击绑定。<h3>这样,每次用户单击任何手风琴时,它都可能会保存先前选择的任务(如果任何属性值已更改)。

希望这可以解决您在触发某些事件时尝试保存任务的情况。

于 2013-09-15T02:36:00.687 回答