I put together a Contacts prototype MVC application that uses Knockoutjs. I'm fairly new to Knockout and was wondering if my design is correct in reaching my end goal. My end goal is basically to take an MVC Model that is passed to my Contacts view to start and achieve the following:
- Mapping it to my KO Viewmodel.
- Use Bootstrap Modal Popup to input my contact data.
- Upon Clicking Add in Bootstrap Modal call template after posting JSON data to controller successfully and have it display under
- Edit button on each template rendered under div if clicked brings up same Modal Popup to edit that templates data.
Here's the code breakdown of what I have currently in place.
View Code
<h2>Contacts List</h2>
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-10"><h3>KO Results</h3></div>
</div>
<br />
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-10"><div id="koResults" data-bind="template: { name: 'contactSectionTmp', foreach:Contacts }"></div></div>
</div>
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-10"><a href="#" id="addContact" class="btn btn-sm btn-success" data-toggle="modal" data-target="#contactModal" data-bind="click: addContact"><strong>Add</strong></a></div>
</div>
@*I enter data in my bootstrap modal shown below and when I click "Add" the Template below appears
in div element koResults with the data I just entered. This is the desired effect I'm looking for. *@
<div class="modal" id="contactModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" style="background-color:#B8E28D; border-color: black">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Add Contact</h4>
</div>
<div class="form-horizontal">
<form id="contactModalForm" data-bind="with:newContact,submit:add">
<div class="modal-body">
<h4>Contact</h4>
<div class="form-group">
<label class="col-sm-4 control-label">Name:</label>
<div class="col-sm-8">
<input type="text" name="Name" class="form-control" data-bind="value: Name" />
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Address:</label>
<div class="col-sm-8">
<textarea rows="4" cols="50" name="Address" class="form-control" data-bind="value: Address"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Phone:</label>
<div class="col-sm-8">
<input type="text" name="Phone" class="form-control" data-bind="value: Phone" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" id="formSubmitContact" class="btn btn-success">Add</button>
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</form>
</div>
</div>
</div>
</div>
@section scripts
<script type="text/javascript" src="~/Scripts/knockout-3.4.0.debug.js"></script>
<script type="text/javascript" src="~/Scripts/knockout.mapping-latest.debug.js"></script>
@* Knockout Template *@
<script id="contactSectionTmp" type="text/html">
<div class="row">
<div class="col-lg-3">Name:</div>
<div class="col-lg-9" data-bind="text: name"></div>
</div>
<div class="row">
<div class="col-lg-3">Address:</div>
<div class="col-lg-9" data-bind="text: address"></div>
</div>
<div class="row">
<div class="col-lg-3">Phone:</div>
<div class="col-lg-9" data-bind="text: phone"></div>
</div>
</script>
End Section
Controller Code
Pass in model to view here.
public ActionResult ContactsList()
{
ContactsVM mData = new ContactsVM();
mData.Contacts = new List<Contact>(){ new Contact { ID = 1, Name="Drew Lucacca", Address="782 Select St.", Phone="421-821-9101"},
new Contact {ID = 2, Name="Kevin Rosassa", Address = "222 Potter Lane", Phone="421-982-5222" },
new Contact {ID = 3, Name="Tim Kropp", Address = "440 PPG Place", Phone="725-434-8989"} };
return View(mData);
}
[HttpPost]
public ActionResult ContactCreate(Contact newContact)
{
var res = newContact;
ContactsVM myContacts = new ContactsVM();
myContacts.Contacts = new List<Contact>();
myContacts.Contacts.Add(new Contact { ID = 4, Name = "Santa Claus", Address = "440 Trump Plaza", Phone = "774-489-8989" });
return Json(myContacts);
}
Javascript Code
` //Main ViewModel
function ContactsVM(data) {
var self = this;
var mapping = {
'Contacts': {
create: function(options) {
return new Contact(options.data);
}
}
};
ko.mapping.fromJS(data, mapping, self);
self.newContact = ko.observable();
self.addContact = function() {
debugger;
self.newContact(new Contact({Name: '', Address: '', Phone: ''}));
}
self.add = function () {
debugger;
var jsData = data;
var jsData1 = ko.mapping.toJSON(self.newContact());
$.ajax({
url: '@Url.Action("ContactCreate", "Home")',
type: 'POST',
data: ko.mapping.toJSON(self.newContact()),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (jsonObject) {
self.contacts.push(new Contact(jsonObject));
}
});
// Close the modal.
$('#contactModal').modal('toggle');
};
self.cancel = function () {
// Close the modal.
$('#contactModal').modal('toggle');
};
//self.resetForm = function (formId) {
// var form = $('#' + formId);
// form.validate().resetForm();
// form.get(0).reset();
//};
};
function Contact(data) {
ko.mapping.fromJS(data, {}, this);
this.isEdit = ko.observable(false);
};
$(function () {
var jsonModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model));
var vm = new ContactsVM(jsonModel);
ko.applyBindings(vm);
});
Contact Entity
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
ContactsVM Entity
public class ContactsVM
{
public List<Contact> Contacts { get; set; }
}
EDIT #1 See here's the thing I know that the javascript isn't correct and note that in javascript comments asking if you can help me identify if it isn't correct how should it be.
I moved the code to new location at bottom of MVC view for the Javascript code didn't seem to find model.
Javascript - Knockout - Mapping Error
JavaScript runtime error: 'push' is undefined
self.contacts.push(new Contact(jsonObject)); < --- Error happens here.
Any help here would be greatly appreciated and I'm sure would help others as well.