【问题标题】:How can I populate a select tag using knockout js and jquery?如何使用淘汰赛 js 和 jquery 填充选择标签?
【发布时间】:2014-01-17 00:52:37
【问题描述】:

我只是想填充几个我用 jquery 呈现的选择标签。

来自服务器的传入模型:

public class DepthChartsVm
{
    public List<DepthChartModel> ReturnDepthCharts {get;set;}
}

public class DepthChartModel
{
    public Team Team {get;set;}
    public int SportId {get;set;}
}

public class Team
{
    // various properties
    public List<AthleteInfo> AthleteInfo {get;set;}
    public List<positions> BasketBallPositonList {get;set;}
}

public class AthleteInfo
{
    // various properties
    List<DepthChart> DepthChartPositions {get;set;}
}

public class DepthChart
{
    // various properties
    prop ...etc
}

public class Positions
{
   // various properties
   prop ... etc.
}

HTML:

                                <div class="col-sm-4">
            <label for="teamDropDown" class="text-center">Teams</label>
            <select id="teamDropDown" data-bind="options: depthVm.ReturnDepthCharts, value: selectedTeam,
                optionsText: function(item){return item.Team.FullName},
                optionsCaption: 'select'"></select>
            <p data-bind="if: selectedTeam">
                <strong>Sport: </strong> <span data-bind="text: selectedTeam().Team.Sport"></span><br />
                <strong>Season: </strong> <span data-bind="text: selectedTeam().Team.Season"></span>
            </p>
        </div>
        <!--Athletes-->
        <div class="col-sm-4">
            <div data-bind="if: selectedTeam">
                <h3 class="text-center">Athletes</h3>
                <div data-bind="foreach: selectedTeam().Team.AthleteInfo">
                    <p>
                        <strong>Name: </strong><span data-bind="text: FirstName()
                            + ' ' + LastName()"></span>
                    </p>
                    <div data-bind="foreach: DepthChartPositions()">
                        <p>
                            <input class="hidden" name="InputUpdateDepthChart.RosterId"
                                   data-bind="value: RosterId"/>
                            Position: <select name="InputUpdateDepthChart.PositionId"
                                    data-bind="options: $root.selectedTeam().Team.BasketBallPostionList, 
                                    optionsText: 'Position', value: PositionId, optionsValue: 'Id'"></select>
                            String: <select name="InputUpdateDepthChart.StringId"
                                    data-bind="options: DepthStrings, optionsText: 'String',
                                        value: StringId, optionsValue: 'Id'"></select>
                        </p>
                        <p>
                            <button data-bind="click: $root.addPosition">Add Position</button>
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    // script that serializes the model and passes it to knockout
    <script>
        // json encode incoming model

        var depthModelData = @Html.Raw(JsonConvert.SerializeObject(Model))

        // update depth chart vM
        ko.applyBindings(new UpdateDepthChartVm(depthModelData),
            document.getElementById('updateDepthChartForm'));
    </script>

查看模型:

                    var UpdateDepthChartVm = function (model) {
var self = this;
self.depthVm = ko.mapping.fromJS(model);

// selected team 
self.selectedTeam = ko.observable();

// add position
self.addPosition = function () {

    self.selectedTeam.Team.AthleteInfo.DepthChartPositions.push(new depthChartPosition());
};

function depthChartPosition(values) {
    values = values || {};
    var model = {
        RosterId: ko.observable(values.RosterId),
        PositionId: ko.observable(values.PositionId),
        StringId: ko.observable(values.StringId),
    };
    return model;
}

};

基本上,当用户希望添加另一个位置时,我会尝试即时复制第一段。 jquery 确实可以使用选择标签呈现新段落,但是选择字段是空的,因为它们与我的视图模型之间似乎没有绑定。除此之外,我的视图模型正在工作。我在这里错过了什么?

【问题讨论】:

    标签: jquery asp.net-mvc knockout.js


    【解决方案1】:

    Knockout Mapping 只会在所提供对象的第一级中的属性周围添加可观察的包装器。我假设您输入ko.mapping.fromJS 方法的对象是DepthChartsVm C# 模型的JS 表示。因此,只有ReturnDepthCharts 属性是可观察的。简单的答案是提供映射自定义,例如:

    var depthChartsVmMapping = {
        Team: {
            create: function(options) {
                return ko.mapping.fromJS(options.data, teamMapping);
            }
        }
    }
    var teamMapping = {
        AthleteInfo: {
            create: function(options) {
                return ko.mapping.fromJS(options.data, athleteInfoMapping);
            }
        }
    }
    var athleteInfoMapping = {
        DeptChartPositions: {
            create: function(options) {
                return ko.mapping.fromJS(options.data);
            }
        }
    }
    
    var self = this;
    self.depthVm = ko.mapping.fromJS(model, depthChartsVmMapping);
    

    是的,我同意这会使映射模块看起来有点负担,但请考虑您的模型包含太多级别的可能性。例如,您真的需要加载所有团队、所有运动员以及每个运动员的深度图位置吗?更传统的类似 REST 的实现可能是在需要时异步加载必要的资源。显然,我不知道您的应用是如何呈现的,但我直觉在这种情况下,您可能会:

    • 一个可观察的团队数组;最初仅包含摘要信息
    • 用于存储当前选定团队的 observable
    • 获取团队详细信息的操作(可能包括带有深度图信息的运动员

    您可以使用上面举例说明的自定义设置进行映射,所以如果您没有关注我,请不要担心。但是,如果您愿意进行一些重构,我会支持这一事业!

    希望有帮助!

    var vm = {
        Teams: ko.observableArray(),
        CurrentTeam: ko.observable(),
    } 
    

    【讨论】:

    • 无论出于何种原因,SO 都不允许我对之前的答案进行修改,所以我不得不提交一个新的。抱歉耽搁了。我希望编辑提交错误能够得到解决。
    • 好的,现在我感觉特别密集。所以我最初理解映射概念,但我对如何将它实际应用到视图模型感到困惑。我的意思是,既然有几个属性需要映射,我是否必须为每个映射调用 ko.mapping ?例如,在上面的代码中你有 self.depthVm = ko.mapping.fromJs(model, modelMappings); modelMappings 在哪里定义?还是我必须一遍又一遍地调用该语句并用每个单独定义的映射替换 modelMapping?
    • 抱歉,modelMappings 出错了。现在更正了。同样,ko 映射不会递归地探索您的模型以在每个级别创建可观察的属性。相反,只有作为提供模型的直接子级的属性是可观察的。这有意义吗?
    • 好的,我现在明白了。感谢您的宝贵时间,您为我提供了一些关于淘汰赛的宝贵见解,就我的模型而言,您是绝对正确的。这确实是问题所在。我有很多数据从服务器返回到一个模型。我将相应地重构我的代码。再次感谢!
    • 很高兴我能为您提供一些价值!当我第一次开始使用 Knockout 构建更多类似 SPA 的应用程序时,我大量使用了 ko.mapping 模块。这些天来,我几乎从不使用它,主要是因为我大量使用 WebAPI 将数据输入我的 UI。祝你好运!
    【解决方案2】:

    后面的选择元素没有任何选项的原因是它们没有被绑定。请记住,ko.applyBindings 可以说是让您的 HTML 栩栩如生。由于这些项目是事后添加的,因此不会被 ko 跟踪。

    实际上有一个更好的方法可以通过淘汰赛的 observableArray 来做到这一点。它更清洁、干燥且可测试。你是如此接近!

    var UpdateDepthChartVm = function (model) {
    var self = this;
    self.depthVm = ko.mapping.fromJS(model);
    
    self.selectedTeam = ko.observable();
    
    self.addPosition = function () {
        self.depthVm.DepthChartPositions.splice(0, 0, new depthChartPosition());
        // I used splice because I believe you were wanting the UI element to be added to the
        // top of the list. Otherwise you could just use `push(new depthChartPosition())`.
    };
    
    // this bit isn't required but it's my preference
    function depthChartPosition(values) {
        values = values || {};
        var model = {
            RosterId: ko.observable(values.RosterId),
            PositionId: ko.observable(values.PositionId),
            StringId: ko.observable(values.StringId),
        }
        return model;
    }
    
    // you also might want to use the above constructor in your mapping. again, just my preference
    function mappings() {
        return {
            DepthChartPositions: {
                create: function(options) {
                    return new depthChartPosition(options.data);
                }
            }
        }
    }
    

    请记住,knockout.js 是一个 MVVM(模型视图视图模型)框架。让视图模型数据驱动 UI,同时让 UI 尽可能简单。

    编辑

    仔细查看您的视图模型,我发现有两个DepthChartPositions:一个是self.depthVm 的成员(由于ko.mapping,它应该是一个observableArray),另一个是selectedTeam().Team.AthleteInfo。后者是 UI 元素绑定到的对象。我确实看到您的 addPosition 函数正在修改正确的对象,但是我不知道这个对象是如何创建的。我的猜测是这不是observableArray。你可以像这样测试它:

    ko.isObservable(self.selectedTeam.Team.AthleteInfo.DepthChartPositions)
    

    【讨论】:

    • 所以我尝试对代码进行建议的更改,但仍然无法正常工作。在这一点上,我怀疑它可能与对象嵌套在我的视图模型中的方式有​​关,所以我更新了上面的 html 以反映整个视图模型。希望这能阐明我在这里做错了什么。同样,一切都在运行,直到 self.addPosition 函数。
    • 你能验证self.selectedTeam.Team.AthleteInfo.DepthChartPositions是一个observableArray吗?
    • 你问错人了,哈哈!但说真的,我现在有点不知所措。我假设它是可以观察到的,因为整个模型是通过 ko.mapping 引入的,但我是全新的淘汰赛,所以我不太确定。
    • 请看我更新的答案。如果有问题的对象实际上是由ko.mapping 创建的,那么到目前为止您发布的代码中不会发生这种情况。你把那个代码漏掉了吗?
    • 所以我从上面的服务器添加了初始模型,以提供一些嵌套的清晰度。我还将脚本添加到上面的 html 代码中以显示初始 ko 绑定。所以我相信你对可观察的东西是正确的。我按照您的建议进行了检查,果然它出现了未定义。因此,我似乎设置它的方式是,一旦用户选择了初始团队,该对象就会通过选项绑定上的 value 参数传递给 selectedTeam 可观察对象。所以我想这就是问题所在。希望这可以澄清一些事情。
    猜你喜欢
    • 2014-02-04
    • 2017-06-09
    • 2020-02-17
    • 2013-01-02
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多