【问题标题】:Binding a table row's button visibility to a function in KnockoutJS将表格行的按钮可见性绑定到 KnockoutJS 中的函数
【发布时间】:2014-02-27 06:32:48
【问题描述】:

我试图弄清楚如何根据 observableArray() 中是否存在特定项目来更改表格中按钮的可见性。

例如,我有一个学生/课程名册,其中包含所有学生的列表和每门课程的注册学生列表。如果学生出现在当前的 EnrolledStudents observableArray 中,我想让“添加”按钮在所有学生列表旁边变得不可见。在我看来,我有:

<tbody data-bind="foreach: AllStudents">
       <tr>
           <td><button data-bind="click: $parent.add, visible: $parent.isEnrolled">Add</button></td>
           <td data-bind="text: StudentId"></td>
           <td data-bind="text: FirstName"></td>
           <td data-bind="text: LastName"></td>
       </tr>
    </tbody>

我遍历 AllStudents 并显示信息以及“添加”按钮。但是,我有一个 isEnrolled 函数来确定特定学生是否注册了当前选择的课程。这是我的功能:

 this.isEnrolled = ko.computed(function (item) {

                    var index = $.inArray(item, self.EnrolledStudents);
                    if (index > -1) {
                        return true;
                    }
                    return false;
                });

问题是,ko.computed() 没有按预期将关联的对象传递给这个函数,这使得item = undefined... 我需要做什么才能使这个函数对每个学生都有效桌子?

这是我的整个 ViewModel.. 没有 jsFiddle 会导致 ajax 调用不起作用。

 function AppViewModel() {
                this.AllStudents = ko.observableArray();
                this.AllCourses = ko.observableArray();
                this.EnrolledStudents = ko.observableArray();
                this.CurrentCourse = ko.observable("1");


                var self = this;

                this.add = function (item) {
                    $.post('/api/Course/AddStudentToCourse?courseId='+self.CurrentCourse()+'&studentId='+item.Id, function (data) {
                        alert("Success");
                        console.log(data);
                        self.EnrolledStudents.push(data);

                    });
                }

                this.remove = function (item) {
                    $.ajax({
                        url: '/api/Course/DeleteStudentFromCourse?courseId='+self.CurrentCourse()+'&studentId='+item.Id,
                        type: 'DELETE',
                        success: function (data) {
                            if (data == true) {
                                self.EnrolledStudents.destroy(item);
                            }
                        }
                    });
                }

                this.isEnrolled = ko.computed(function () {

                    var index = $.inArray(item, self.EnrolledStudents);
                    if (index > -1) {
                        return true;
                    }
                    return false;
                }, this);

                $.get('/api/Course/AllStudents', this.AllStudents);
                $.get('/api/Course/AllCourses', this.AllCourses);



                $('select').change(function () {
                    self.CurrentCourse($('select option:selected').val());

                    if (self.CurrentCourse() != "") {
                        $.get('/api/Course/StudentsByCourse', { id: self.CurrentCourse() }, self.EnrolledStudents);
                    }
                });

            }

            ko.applyBindings(new AppViewModel());

【问题讨论】:

  • 能否请您展示您的整个视图模型或制作小提琴?
  • 好的,我更新了帖子
  • 你是在检查学生是否被录取还是其他情况是否属实?

标签: knockout.js


【解决方案1】:

visible 绑定默认情况下不会像click 绑定一样将当前对象作为参数传入。你需要做的是这样的:

<tbody data-bind="foreach: AllStudents">
   <tr>
       <td><button data-bind="click: $parent.add, visible: $parent.checkIsEnrolled( $data )">Add</button></td>
       <td data-bind="text: StudentId"></td>
       <td data-bind="text: FirstName"></td>
       <td data-bind="text: LastName"></td>
   </tr>
</tbody>

然后将此函数添加到您的视图模型以验证当前对象是否已注册:

self.checkIsEnrolled = function( item ) {
     var index = self.EnrolledStudents.indexOf( item );
     if (index > -1) {
          return false;
     }
     return true;
}

另一个与可见无关的问题是删除函数实际上应该使用remove 方法而不是destroy

这是使用此功能的更新小提琴:

http://jsfiddle.net/7J8XR/4/

上下文变量的完整列表在这里:

http://knockoutjs.com/documentation/binding-context.html

【讨论】:

  • 我在尝试Uncaught Error: Unable to process binding "visible: function (){return $parent.isEnrolled($data) }" Message: Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.时收到此错误@
  • 我不想“写入”到 isEnrolled 变量中。我只希望数据的上下文进行搜索
  • 对不起,我错过了,我刚刚更新了答案以使用函数而不是计算。
  • 哦,那你就用普通函数吧?好的听起来很容易
  • 对于这个特定的实例,如果可见属性没有直接绑定到当前循环中的对象,我可能会这样做。另一种选择是使 isEnrolled 在子(学生)模型中计算并让其检查父模型以查看它是否在 Enrolled 数组中
【解决方案2】:

*不是马特问题的合适答案,因为它不符合他检索注册学生的方式 - 我把这个留在这里是为了感兴趣,请参阅评论 ****

作为替代方案(因为它可以实现您的目标并保持清洁),您可以在首次创建 AllStudents 可观察数组时向学生添加一个 isEnrolled 可观察属性:

this.AllStudents=ko.observableArray(ko.utils.arrayMap(students,function(student){
     student.isEnrolled = ko.observable(false);
    return student;
}));

然后,当您单击添加时,将 isEnrolled 属性设置为 true:

this.add = function (item) {

   item.isEnrolled(true);
   self.EnrolledStudents.push(item);
}

您在表格行上的 html 将像这样工作:

<tr data-bind="visible:!isEnrolled()">

最后在您的删除点击中,将 isEnrolled 设置为 false (并使用 .remove(item) 而不是如 hereswhatIdid 在他的回答中指出的那样销毁:

this.remove = function (item) {

    item.isEnrolled(false);               
    self.EnrolledStudents.remove(item);
}

小提琴可以在这里找到:http://jsfiddle.net/jiggle/823v5/

希望对你有帮助。

【讨论】:

  • 马特,在第二次阅读您的问题和视图模型时,我的答案不适合 - 尽管希望无论如何都会引起兴趣。我已经在 hereswhatidid 中回答了您关于让小提琴正常工作的评论(小提琴设置问题,并且还需要!)问候。
猜你喜欢
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 2012-09-06
  • 2010-09-27
  • 1970-01-01
相关资源
最近更新 更多