Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Posting Collection with Knockout.js

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

Project ViewModel


ProjectServicesViewModel


ProjectPositionsViewModel

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

Design

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?

Result

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!

like image 288
Daniil T. Avatar asked Sep 22 '16 06:09

Daniil T.


2 Answers

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.

like image 176
jmvtrinidad Avatar answered Nov 15 '22 14:11

jmvtrinidad


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.

like image 43
Daniil T. Avatar answered Nov 15 '22 15:11

Daniil T.