【问题标题】:knockout check all checkboxes in table column剔除检查表格列中的所有复选框
【发布时间】:2021-08-27 17:22:38
【问题描述】:

我是淘汰赛的新手,并试图实现一个表,其中第一列作为复选框。当我单击标题时,应选中/取消选中整个列。目前,当我单击表格行(所有行都被选中/未选中)但不在表格标题上时,它可以工作。请让我知道我的代码有什么问题!这是我的部分代码:

        <table>
            <tr>
                <th><input type="checkbox" data-bind="click: selectAll"></th>
                <th>Notes</th>
            </tr>
        
            <tbody data-bind="foreach: DocumentRows">
                <tr>
                    <td><input type="checkbox" data-bind="checked: $parent.IsSelected"></td>
             <td><data-bind="text: Notes"></td>
</tr>
            </tbody>
        </table>
        
       // Script.ts
        
        ```
        define(['knockout', 'jquery', 'text!./Template'], (ko, $, htmlString) => {
        //Document
        class Document {
                Id: KnockoutObservable<number>;      
                Notes: KnockoutObservable<string>;        
                constructor(data?) {
                    this.Id = ko.observable(0);          
                    this.Notes = ko.observable("").extend({ defaultValue: "" });            
                    if (data != null) {
                        ko.mapping.fromJS(data, {}, this);
                    }
                }        
            };
        
        
        //DocumentS VIEW MODEL
        class DocumentsViewModel {
        DocumentRows: KnockoutObservableArray<Document>;
        IsSelected: KnockoutObservable<boolean>;
               
        constructor(params) {
        this.DocumentRows = ko.observableArray([]);
        this.IsSelected = ko.observable(false);//
        this.InitComputed();       
               this.Load();
        }
        InitComputed = () => {
        selectAll = (Document: DocumentsViewModel) => {      
                    var doc = Document.DocumentRows;           
                    ko.utils.arrayForEach(doc(), function (item) {
                        item.IsSelected(true);
                    });
                }
        
        Load = () => {
                    DocumentsApiService.GetDocumentList(this);
                }
        
        }
        
        //API SERVICE
        class DocumentsApiService {
                static GetDocumentList = (model: DocumentsViewModel) => {
                    $.ajax({
                        url: buildUrl(model.LoadListURL, { 'id': model.ObjectId(), 'additionalId': model.AdditionalId() }),
                        type: 'POST',
                        data: ko.mapping.toJSON(model.Filter),
                        contentType: 'application/json; charset=utf-8'
                    }).done(allData => {
                        var mapped = ko.mapping.fromJS(allData, DocumentsMapping);
                        model.DocumentRows(mapped.DocumentRows());
                        model.Filter.TotalCount(mapped.TotalCount());
                        model.Filter.PageIndex(mapped.Filter.PageIndex());
                        CalcCountTableStatus(model.Filter.PageIndex(), model.Filter.PageSize(), model.Filter.TotalCount(), 'documents-count-status-line');
                    }).fail(data => {
                        TSCore.OnFailure(data);
                    });
                }
        }
        
            return { viewModel: DocumentsViewModel, template: htmlString }
        });
        ```

【问题讨论】:

    标签: foreach knockout.js


    【解决方案1】:

    在实现这样的选择功能时,通常有两种方法。

    Document 级别有一个isSelected 布尔可观察对象

    isSelected observable 放在Document 模型上,而将no 放在DocumentsViewModel 上,因为无论是否被选中,每个文档都必须包含信息。

    我猜您正在尝试实施这种方法,但乍一看,您没有在正确的位置使用IsSelected。此外,如果您将IsSelected 移动到文档中,那么在您的视图中不要使用$parent.IsSelected,而只需使用IsSelected

    DocumentsViewModel 级别维护一个selectedDocuments 可观察文档数组

    通过这种方式,您可以获得所有当前选定文档的可观察数组,并在选择所有文档时保持该数组(例如将所有行推送到选择中)

    在您看来,您必须使用父引用来确定文档是否被选中,例如$parent.selectedDocuments.indexOf($data) &gt;= 0

    我暂时不会介绍这两种方法的所有优缺点,但我建议您使用第一种,如果您可以使用 IsSelected observable 扩展您的文档模型。

    其他说明

    不太清楚你想用InitComputeds 东西实现什么。为什么不将这些操作作为视图模型类的函数,例如

    public selectAll(): void {      
        ko.utils.arrayForEach(this.DocumentRows(), function (item) {
            item.IsSelected(true);
        });
    }
    

    如果使用此语法,则必须在视图级别绑定函数,如$data.selectAll.bind($data)。如果你不想这样,而你只想要selectAll,那么你可以使用箭头函数作为这样的字段语法。

    public selectAll = ():void => {
        ko.utils.arrayForEach(this.DocumentRows(), function (item) {
            item.IsSelected(true);
        });
    }
    

    希望我能提供一些有价值的提示。

    【讨论】:

    • 非常感谢您回答这个问题 - 我已根据您的建议进行了更改,现在可以使用了。需要进行更多调整以检查/取消选中列标题,因为现在由于某种原因它仍然未选中。
    • 很高兴我能帮上忙。您可能可以创建一个计算值,它会告诉您是否选择了所有项目。您可以将其绑定到标题复选框。
    • 所以,我把tbody改成了这个
    • 任何进一步的帮助将不胜感激@Zoltán Tamási
    • @Anna 从这里很难说出这个问题。例如,请从您在 jsfiddle 中的代码中准备一个示例,然后我会尝试看看。
    【解决方案2】:

    所以,修改后 表头:

    <th><input type="checkbox" data-bind="click: selectAll, checked: selectedAll"></th>
    

    表体:

     <td><input type="checkbox" data-bind="checked: IsSelected"></td>
    

    脚本:

        //Document
    class Document {
        Id: KnockoutObservable<number>;        
        IsSelected: KnockoutObservable<boolean>;
        constructor(data?) {
            this.Id = ko.observable(0);
            this.Notes = ko.observable("").extend({ defaultValue: "" });          
            this.IsSelected = ko.observable(false);
            if (data != null) {
                ko.mapping.fromJS(data, {}, this);
            }
        }
    };
    

    //文档视图模型

         class DocumentsViewModel {
        selectedAll: KnockoutObservable<boolean>;
      constructor(params) {
     this.selectedAll = ko.observable(false);
    }
     InitComputed = () => {
    this.selectedAll = ko.pureComputed({
                    read: function () {
                        return this.selectedIds().length === this.DocumentRows().length;
                    },
                    write: function (value) {
                        this.selectedIds(value ? this.DocumentRows.slice(0) : []);
                    },
                    owner: this
                }
         selectAll = (): void => {
                    if (this.selectedIds().length > 0) {
                        this.selectedIds.removeAll();
                        ko.utils.arrayForEach(this.DocumentRows(), function (item) {
                            item.IsSelected(false);
                        });
                    } else {
                        ko.utils.arrayPushAll(this.selectedIds(), this.DocumentRows())
                        ko.utils.arrayForEach(this.DocumentRows(), function (item) {
                            item.IsSelected(true);
                        });
                    }
                }
        }
    

    当所有行都被选中或未选中时,它不显示要检查的标题。请问我哪里出错了?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 2012-12-12
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      相关资源
      最近更新 更多