在嵌套的observablearrays中调用函数(knockout.js)

时间:2014-02-01 23:52:14

标签: javascript knockout.js

我有一个带有几个嵌套observableArrays的视图模型,我需要调用一个函数来从一个数组中删除项目。我将尝试用英语描述模型,而不是图表(它也包含在下面的代码中)。视图模型是一个训练计划,它有一个可观察的周对象阵列。除了其他属性之外,每周对象都有一个observableArray of Days对象。除了其他属性之外,每天对象都有一个可观察的Workout对象数组。除其他属性外,每个训练对象都有一个observableArray of Interval对象。我是淘汰赛的新手,而不是那些稳定在我脚下的javascript(所以可能在这里做错了一些,请随意批评)。问题在于Day对象上的removeWorkout函数。我在淘汰赛网站上关注示例2:example。我认为我正在做页面所说的内容,但是当我在函数中检查“this”时,它是一个Day对象而不是调用该函数的Workout对象。我哪里错了?

我的javascript文件:

  $(document).ready(function() {  
        var trainingPlan;
        var weekNumber = 0;
        var workoutNumber = 0;    
        var planID = { id: $('#ID').val() };

        $.getJSON('/PlanBuilder/GetPlanJson', planID, function (model) {
        trainingPlan = ko.mapping.fromJSON(model.Message);

        trainingPlan.addWeek = function() {
            var wk = new week();

            weekNumber++;
            wk.Name = 'Week ' + weekNumber;

            for (var i = 1; i < 8; i++) {
                var dy = new day();
                dy.DayNumber = i;
                wk.Days.push(dy);
            }

            var summ = new day();
            summ.DayNumber = "Summary";
            wk.Days.push(summ);

            this.Schedule.push(wk);
        };

        ko.applyBindings(trainingPlan);
    });

    function week() {
        this.PlanID = ko.observable();
        this.StartDate = ko.observable();
        this.EndDate = ko.observable();
        this.Name = ko.observable();
        this.Days = ko.observableArray(); // a list of day objects
    };

    function day() {
        var self = this;

        self.DayNumber = ko.observable();
        self.TodaysDate = ko.observable();
        self.Name = ko.observable();
        self.Workouts = ko.observableArray(); // a list of workout objects
        self.addWorkout = function () {
            var wrk = new workout();
            wrk.Type = "Workout " + workoutNumber++;
            self.Workouts.push(wrk);
        };
        self.removeWorkout = function () {
            // 'this' should represent the item that originated the call (a workout)  Not the case...
            self.Workouts.remove(this);
        };
    };

    function workout() {
        this.Type = ko.observable(); //need to figure out what/how to handle enums
        this.WarmUp = ko.observableArray(); // a list of intervals
        this.Main = ko.observableArray(); // a list of intervals
        this.CoolDown = ko.observableArray(); // a list of intervals
        this.Status = ko.observable();
        this.Completed = ko.observable();
    };

    function interval() {
        this.timeValue = ko.observable();
        this.timeUnit = ko.observable();
        this.rpeUnits = ko.observable();
        this.heartRateZone = ko.observable();
        this.description = ko.observable();
        this.distanceValue = ko.observable();
        this.distanceUnit = ko.observable();
    };
});

我的观点:

<div class="container">
    <div class="page-header">
        <h2>@ViewBag.HeaderText</h2>
    </div>

    <div class="panel panel-default">
        <div class="panel-heading">
            <h3>Plan Summary</h3>
        </div>
        <div class="panel-body">
            <div id="NewPlanForm" class="form-horizontal">
                @Html.AntiForgeryToken()
                @Html.HiddenFor(model => model.ID )
                <div class="form-group">
                    @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextBoxFor(model => model.Name, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Name)
                    </div>
                </div>

                <div class="form-group">
                    @Html.LabelFor(model => model.Author, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextBoxFor(model => model.Author, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Author)
                    </div>
                </div>

                <div class="form-group">
                    @Html.LabelFor(model => model.ShortDescription, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextBoxFor(model => model.ShortDescription, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.ShortDescription)
                    </div>
                </div>

                <div class="form-group">
                    @Html.LabelFor(model => model.LongDescription, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextAreaFor(model => model.LongDescription, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.LongDescription)
                    </div>
                </div>

                <div class="form-group">
                    @Html.LabelFor(model => model.Discipline, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextBoxFor(model => model.Discipline, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Discipline)
                    </div>
                </div>

                <div class="form-group">
                    @Html.LabelFor(model => model.Level, new { @class = "control-label col-md-3" })
                    <div class="col-md-9">
                        @Html.KnockoutTextBoxFor(model => model.Level, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Level)
                    </div>
                </div>
            </div>
            <div class="pull-right">
                <div id="btnSavePlan" class="btn btn-primary">Save Plan</div>
            </div>
        </div>
    </div>
</div>

<div id="SchedulePanel" class="panel panel-default">
    @Html.HiddenFor(model => model.ID)
    <div class="panel-heading">
        <h3>Plan Schedule</h3>
    </div>
    <div class="panel-body">
        <div class="pull-right">
            <input id="numWeeks" type="text" class="form-control input-sm" placeholder="number"/>
            <a id="btnAddWeek" class="btn btn-primary" data-bind="click: addWeek">Add Week(s)</a>
        </div>
        <div id="ScheduledInstructions">
            Click the Add Week button to get started adding workouts to your schedule
        </div>
        <hr />
        <div id="weeks" data-bind="template: { name: 'weekTemplate', foreach: Schedule}">
        </div>
    </div>
</div>

<script id="weekTemplate" type="text/html">
    <div style=" margin-left: auto; margin-right: auto; ">
        <h4 data-bind="text: Name"></h4>
        <div data-bind="id: weekName, template: { name: 'dayTemplate', foreach: Days }" >
        </div>
    </div>
</script>

<script id="dayTemplate" type="text/html">
    <div class="dayBuilder">
        <span data-bind="text: DayNumber"></span>
        <div data-bind="id: dayName, template: { name: 'workoutTemplate', foreach: Workouts }" >
        </div>
        <div class="addWorkout">
            <span class="glyphicon glyphicon-plus" data-bind="click: addWorkout" title="Add Workout"></span>
        </div>
    </div>   
</script>

<script id="workoutTemplate" type="text/html">
    <div class="workout">
        <span data-bind="text: Type"></span>
        <span class="glyphicon glyphicon-remove pull-right" data-bind="click: $parent.removeWorkout"></span>
    </div>
</script>

1 个答案:

答案 0 :(得分:1)

removeWorkout()&#34;属于&#34;到$parent,这是一天,而不是锻炼;因此this是一个日期对象。 Knockout将发起调用的模型作为第一个参数提供,因此这应该有效......

self.removeWorkout = function (workout) {
    // 'this' should represent the item that originated the call (a workout)  Not the case...
    self.Workouts.remove(workout);
};

编辑:这是文档(参见注释1)...... Knockout: The "click" binding