Harambe
Harambe

Reputation: 997

KnockoutJS - Nested JSON objects

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.

Upvotes: 0

Views: 417

Answers (1)

peco
peco

Reputation: 4000

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);
}

Upvotes: 1

Related Questions