0

I am trying to expand my knowledge of KnockoutJS (I have a high level understanding). I am building a C# project using Web API to handle Data Access -> Presentation Layer, however I have encountered some problems with my view model, and I do know it's something I have done wrong, so was hoping someone could help me out and explain what I've done?

We're going off to get a 'Lesson' from the Database, and return it in JSON. Here is the class:

Lesson.cs

using System;

namespace TestApplication.Model
{
    public class Lesson
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual Teacher Teacher { get; set; }
        public virtual Classroom Classroom { get; set; }
        public virtual Subject Subject { get; set; }
        public virtual DateTime StartTime { get; set; }
        public virtual DateTime EndTime { get; set; }
    }
}

If I go directly to the Web API route, here's the returned lessons:

Lessons.JSON

[  
 {  
  "id":1,
  "name":"Lesson 1",
  "teacher":{  
     "id":3,
     "firstName":"Sophie",
     "lastName":"Adams",
     "emailAddress":"[email protected]"
  },
  "classroom":{  
     "id":1,
     "name":"Great Hall"
  },
  "subject":{  
     "id":4,
     "name":"jQuery"
  },
  "startTime":"2016-02-10T09:30:00",
  "endTime":"2016-02-10T10:30:00"
},
{  
  "id":2,
  "name":"Lesson 2",
  "teacher":{  
     "id":4,
     "firstName":"Tristan",
     "lastName":"Sanchez",
     "emailAddress":"[email protected]"
  },
  "classroom":{  
     "id":2,
     "name":"Room 1A"
  },
  "subject":{  
     "id":3,
     "name":"SQL"
  },
   "startTime":"2016-02-10T09:00:00",
  "endTime":"2016-02-10T10:30:00"
}
]

And finally, here's my KnockoutModel:

LessonsViewModel.js

var lessonRegisterViewModel;

function Lesson(id, name, teacher, room, subject, startTime, endTime) {
    var self = this;
    self.Id = ko.observable(id);
    self.Name = ko.observable(name);
    self.Teacher = ko.observable(teacher);
    self.Room = ko.observable(room);
    self.Subject = ko.observable(subject);
    self.StartTime = ko.observable(startTime);
    self.EndTime = ko.observable(endTime);
    self.addLesson = function() {
        var dataObject = ko.toJSON(this);
        $.ajax({
            url: '/api/Lessons',
            type: 'post',
            data: dataObject,
            contentType: 'application/json',
            success: function(data) {
                lessonRegisterViewModel.lessonListViewModel.lessons.push(new Lesson(data.Id, data.Name, data.Teacher, data.Room, data.Subject, data.StartTime, data.EndTime));
                self.Id(null);
                self.Name('');
                self.Teacher('');
                self.Room('');
                self.Subject('');
                self.StartTime('');
                self.EndTime('');
            }
        });
    }
}

function LessonList() {
    var self = this;
    self.lessons = ko.observableArray([]);
    self.getLessons = function() {
        self.lessons.removeAll();
        $.getJSON('/api/Lessons', function(data) {
            $.each(data, function(key, value) {
                self.lessons.push(new Lesson(value.id, value.name, value.teacher, value.room, value.subject, value.startTime, value.endTime));
                console.log(self);
            });
        });
    };
    self.removeLesson = function(lesson) {
        $.ajax({
            url: '/api/Lessons/' + lesson.Id(),
            type: 'delete',
            contentType: 'application/json',
            success: function() {
                self.lessons.remove(lesson);
            }
        });
    }
}
lessonRegisterViewModel = {
    addLessonViewModel: new Lesson(),
    lessonListViewModel: new LessonList()
};
$(document).ready(function() {
    // bind view model to referring view
    ko.applyBindings(lessonRegisterViewModel);
    // load lesson data
    lessonRegisterViewModel.lessonListViewModel.getLessons();
});

Bindings for the number of lessons, name, start and end times work fine, it's just the nested objects and how I map those to get the values I need from those classes is the pain here, but any general improvements / constructive criticism is welcome too.

4
  • Are you interested in all of the information for the teacher, or just a name or? Commented Feb 11, 2016 at 15:38
  • You can get any value on the teacher by doing something like teacher.firstName. If you want a particular section of HTML dedicated to teacher information you could use the with binding. <div data-bind="with: teacher"><span data-bind="text: firstName"></span></div> Commented Feb 11, 2016 at 15:41
  • Hi Mike, can I put the with and the text in one element? Just interested more than anything. Going to give your suggestion a go now. Commented Feb 11, 2016 at 16:10
  • Mike, appreciate that - Works a treat. Commented Feb 11, 2016 at 16:57

1 Answer 1

1

You could define seperate models for the nested objects:

function Lesson(id, name, teacher, room, subject, startTime, endTime) {
    var self = this;
    self.Id = ko.observable(id);
    self.Name = ko.observable(name);
    self.Teacher = new Teacher(teacher);
    self.Room = new Classroom(room);
    self.Subject = new Subject(subject);
    self.StartTime = ko.observable(startTime);
    self.EndTime = ko.observable(endTime);

    //....
}

function Teacher(t) {
    var self = this;
    self.Id = ko.observable(t.id);
    self.FirstName = ko.observable(t.firstName);
    self.LastName = ko.observable(t.lastName);
    self.EmailAddress = ko.observable(t.emailAddress);
}

function Classroom(c) {
    var self = this;
    self.Id = ko.observable(c.id);
    self.Name = ko.observable(c.name);
}

function Subject(s) {
    var self = this;
    self.Id = ko.observable(s.id);
    self.Name = ko.observable(s.name);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.