I'm writing an asp.net MVC application and decide to try Knockout.js for dynamic UI stuff. It's a great framework it helped me so much so far.
But I faced 2 problems that I can't solve and find any useful information on that. I'll start with code to show you what I have and then I shall try to explain what I want to achieve.
C# ViewModel
My HTML/Razor and knockout Module
var Project = function (project) {
var self = this;
self.Id = ko.observable(project ? project.Id : 0);
self.CustumerCompany = ko.observable(project ? project.CustumerCompany : "");
self.CustomerRepresentative = ko.observable(project ? project.CustomerRepresentative : "");
self.ProjectTitle = ko.observable(project ? project.ProjectTitle : "");
self.WWSNumber = ko.observable(project ? project.WWSNumber : "");
self.AqStatus = ko.observable(project ? project.AqStatus : "");
self.Completed = ko.observable(project ? project.Completed : "");
self.StartDate = ko.observable(project ? project.StartDate : "");
self.EndDate = ko.observable(project ? project.EndDate : "");
self.ProjectLeader = ko.observable(project ? project.ProjectLeader : "");
self.Deputy = ko.observable(project ? project.Deputy : "");
self.SalesConsultant = ko.observable(project ? project.SalesConsultant : "");
self.Service = ko.observableArray(project ? project.Service : []);
};
var ProjectService = function (projectService) {
var self = this;
self.Id = ko.observable(projectService ? projectService.Id : 0);
self.Number = ko.observable(projectService ? projectService.Number : "");
self.Name = ko.observable(projectService ? projectService.Name : "");
self.Positions = ko.observableArray(projectService ? projectService.Positions : []);
};
var ServicePosition = function (servicePosition) {
var self = this;
self.Id = ko.observable(servicePosition ? servicePosition.Id : 0);
self.Number = ko.observable(servicePosition ? servicePosition.Number : "");
self.Name = ko.observable(servicePosition ? servicePosition.Name : "");
self.PerformanceGroup = ko.observable(servicePosition ? servicePosition.PerformanceGroup : "");
self.PerformanceGroupPrice = ko.observable(servicePosition ? servicePosition.PerformanceGroupPrice : "");
self.Remarks = ko.observable(servicePosition ? servicePosition.Remarks : "");
};
var ProjectCollection = function () {
var self = this;
self.project = ko.observable(new Project());
self.projectServices = ko.observableArray([new ServicePosition()]);
self.servicePositions = ko.observableArray([new ServicePosition()]);
self.addService = function () {
self.projectServices.push(new ProjectService());
console.log(self.projectServices);
};
self.removeService = function (projectService) {
self.projectServices.remove(projectService);
};
self.saveProject = function () {
self.project().Service = self.projectServices;
console.log(self.projectServices);
console.log(self.project());
var token = $('[name=__RequestVerificationToken]').val();
$.ajax({
type: "POST",
url: "/LeistungManager/CreateProject",
data: { __RequestVerificationToken: token, model: ko.toJS(self.project()) },
dataType: "json",
cache: false,
async: true,
success: function (response) {
},
complete: function (response) {
console.log(response);
}
});
};
};
ko.applyBindings(new ProjectCollection());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="row">
<div class="col-md-6">
<div class="widget">
<div class="widget-heading">
<h3 class="widget-title">Project Services</h3>
<div>
<form class="form-inline">
<p>
<div class="form-group">
<label>WWS-Number</label>
<input class="form-control" placeholder="Number" data-bind="value: $root.Number" />
<label>WWS-Number</label>
<input class="form-control" placeholder="Name" data-bind="value: $root.Name" />
<button class="btn btn-primary" data-bind="click: addService">Add</button>
</div>
</p>
</form>
</div>
</div>
<div class="widget-body">
<table data-bind="visible: projectServices().length > 0 " class="table">
<thead>
<tr>
<th>
Number
</th>
<th>
Service Name
</th>
<th>
</th>
</tr>
</thead>
<tbody data-bind="foreach: projectServices">
<tr>
<td data-bind="text: $parent.Number"></td>
<td data-bind="text: $parent.Name"></td>
<td>
<button class="btn btn-success">Edit</button>
<button class="btn btn-danger" data-bind="click: $root.removeService">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
My Result looks like
Problem Nr 1
When I enter all information and adding few project services item's my controller receive model but Service's properties are empty and I can't figure out why? What I'm doing wrong?
Problem Nr 2
Next to Project Service panel ( see design screenshot ) I will build another almost the same panel but in that window the same Add To List functionality should depend on which Item I select in Project Service Panel. For example:
If I selected first item in Project Service panel on the right should appear panel with ADD button so I can put item to another list. After I put information to one item I can selected another and put there and panel should update based on Project Service selection. I can't find anywhere example, article or tutorial how to achieve this kind of result. Any kind of help with be helpful!
For your:
Problem 1 you can add contentType: 'application/json;'
in your ajax request for the controller to know how to parse your request.
Problem 2 see this fiddle for example of your code. You can check this documentation in order for you to know where to use different binding context.
After some time reading documentation I manage to solve my problem. So here is working JS code HTML is the same as in my question:
/// <reference path="../jquery-3.1.0.intellisense.js" />
var ProjectModel = function (project) {
var self = this;
self.Id = ko.observable(project ? project.Id : 0);
self.CustumerCompany = ko.observable(project ? project.CustumerCompany : "");
self.CustomerRepresentative = ko.observable(project ? project.CustomerRepresentative : "");
self.ProjectTitle = ko.observable(project ? project.ProjectTitle : "");
self.WWSNumber = ko.observable(project ? project.WWSNumber : "");
self.AqStatus = ko.observable(project ? project.AqStatus : "");
self.Completed = ko.observable(project ? project.Completed : "");
self.StartDate = ko.observable(project ? project.StartDate : "");
self.EndDate = ko.observable(project ? project.EndDate : "");
self.ProjectLeader = ko.observable(project ? project.ProjectLeader : "");
self.Deputy = ko.observable(project ? project.Deputy : "");
self.SalesConsultant = ko.observable(project ? project.SalesConsultant : "");
self.Service = ko.observableArray(project ? project.Service : []);
};
// #endregion
// #region Project Service Model
var ProjectServiceModel = function (projectService) {
var self = this;
self.Id = ko.observable(projectService ? projectService.Id : 0);
self.Number = ko.observable(projectService ? projectService.Number : "");
self.Name = ko.observable(projectService ? projectService.Name : "");
self.Positions = ko.observableArray(projectService ? projectService.Positions : []);
self.isEditing = ko.observable(true);
self.isActive = ko.observable(false);
self.countSelf = ko.computed(function () {
if (self.Positions().length > 0) {
return true;
}
else {
return false;
}
},
self);
};
// #endregion
// #region Position Model
var ServicePositionModel = function (servicePosition) {
var self = this;
self.Id = ko.observable(servicePosition ? servicePosition.Id : 0);
self.Number = ko.observable(servicePosition ? servicePosition.Number : "");
self.Name = ko.observable(servicePosition ? servicePosition.Name : "");
self.PerformanceGroup = ko.observable(servicePosition ? servicePosition.PerformanceGroup : "");
self.PerformanceGroupPrice = ko.observable(servicePosition ? servicePosition.PerformanceGroupPrice : "");
self.Remarks = ko.observable(servicePosition ? servicePosition.Remarks : "");
self.isEditing = ko.observable(servicePosition ? servicePosition.isEditing : false);
self.isActive = ko.observable(false);
};
// #endregion
var ProjectViewModel = function () {
var self = this;
self.project = ko.observable(new ProjectModel());
self.projectServices = ko.observableArray([]);
// #region InitData
self.selectedPerformanceGroup = ko.observableArray([]);
self.AqStatusTypeData = ko.observableArray([]);
self.PerformanceGroupTypeData = ko.observableArray([]);
$.ajax({
url: "/LeistungManager/InitializeData",
dataType: "json",
success: function (json) {
self.AqStatusTypeData(json.AqStatusType);
self.PerformanceGroupTypeData(json.PerformanceGroupType);
}
});
self.testOptions = function () {
self.selectedPerformanceGroup;
debugger;
}
// #endregion
// #region Service Functions
self.addService = function () {
var object = new Object();
object.isEditing = true;
self.projectServices.push(new ProjectServiceModel(object));
self.isServiceSelected(false);
};
self.saveService = function (projectService) {
projectService.isEditing(false);
};
self.editService = function (projectService) {
projectService.isEditing(true);
};
self.removeService = function (projectService) {
self.projectServices.remove(projectService);
};
self.isServiceSelected = ko.observable(false);
self.selectedServiceData = ko.observable(new Object());
self.selectService = function (serviceRowData) {
if (!serviceRowData.isEditing()) {
self.isServiceSelected(true);
serviceRowData.isActive(true);
self.selectedServiceData(serviceRowData);
}
};
// #endregion
// #region Position Functions
self.addPosition = function () {
var object = new Object();
object.isEditing = true;
self.selectedServiceData().Positions.push(new ServicePositionModel(object));
};
self.savePosition = function (servicePosition) {
servicePosition.isEditing(false);
};
self.editPosition = function (servicePosition) {
servicePosition.isEditing(true);
};
self.removePosition = function (servicePosition) {
self.selectedServiceData().Positions.remove(servicePosition);
};
self.isPositionSelected = ko.observable(false);
self.selectedPositionData = ko.observable(ServicePositionModel(new Object()));
self.selectPosition = function (positionRowData) {
if (!positionRowData.isEditing()) {
self.isPositionSelected(true);
positionRowData.isActive(true);
self.selectedPositionData(positionRowData);
}
};
// #endregion
self.saveProject = function () {
self.project().Service = self.projectServices;
self.project().Service().Positions = self.servicePositions;
var token = $('[name=__RequestVerificationToken]').val();
$.ajax({
type: "POST",
url: "/LeistungManager/CreateProject",
data: { __RequestVerificationToken: token, model: ko.toJS(self.project()) },
dataType: "json",
cache: false,
async: true,
success: function (response) {
},
complete: function (response) {
console.log(response);
}
});
};
};
ko.applyBindings(new ProjectViewModel());
The magic was with creating selectedServiceData observable variable and pass it to selectPosition function on button click. After that I could work with selected Item arrays and data.
If anybody needs more detailed explanation or help with code - let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With