POST model using KnockoutJS is different from API model - api

I have an issue with the model on post. The collection of 'EmployeeDetailses' is null when the model is posted using Ajax calls. I checked it with Fiddler but the JSON model is actually good. The problem is with the model passed as parameter to controller.
var EmployeeViewModel = function () {
// Make the self as 'this' reference
var self = this;
// Declare observable which will be bind with UI
self.EmployeeId = ko.observable("");
self.FirstName = ko.observable("");
self.MiddleName = ko.observable("");
self.Tussenvoegsel = ko.observable("");
self.LastName = ko.observable("");
self.FullName = ko.observable("");
self.EmployeeEmail = ko.observable("");
self.PersonalNumber = ko.observable("");
self.PhoneNumber = ko.observable("");
//The Object which stored data entered in the observables
var EmployeeData = {
EmployeeId: self.EmployeeId,
FirstName: self.FirstName,
MiddleName: self.MiddleName,
Tussenvoegsel: self.Tussenvoegsel,
LastName: self.LastName,
FullName: self.FullName,
EmployeeEmail: self.EmployeeEmail,
EmployeeDetailses: {
PhoneNumber: self.PhoneNumber,
PersonalNumber: self.PersonalNumber
}
};
// Declare an ObservableArray for Storing the JSON Response
self.Employees = ko.observableArray([]);
GetEmployees(); // Call the Function which gets all records using ajax call
// Function to Read All Employees
function GetEmployees() {
// Ajax Call Get All Employee Records
$.ajax({
type: "GET",
url: "/api/EmployeeApi",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
self.Employees(data); // Put the response in ObservableArray
},
error: function (error) {
alert(error.status + "<--and--> " + error.statusText);
}
});
// Ends Here
}
// Function to Display record to be updated
self.getEmployeeDetails = function (employee) {
self.EmployeeId(employee.EmployeeId),
self.FirstName(employee.FirstName),
self.MiddleName(employee.MiddleName),
self.Tussenvoegsel(employee.Tussenvoegsel),
self.LastName(employee.LastName),
self.FullName(employee.FullName),
self.EmployeeEmail(employee.EmployeeEmail),
self.PersonalNumber(employee.EmployeeDetailses[0].PersonalNumber),
self.PhoneNumber(employee.EmployeeDetailses[0].PhoneNumber)
};
// Function to perform POST (insert Employee) operation
self.save = function () {
// Ajax call to Insert the Employee
$.ajax({
type: "POST",
url: "/api/EmployeeApi",
contentType: "application/json",
dataType: "json",
data: ko.mapping.toJSON(EmployeeData), // Convert the Observable Data into JSON
success: function () {
alert("Record Added Successfully");
GetEmployees();
},
error: function () {
alert("Failed");
}
});
// Ends Here
};
};
ko.applyBindings(new EmployeeViewModel());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
#using Resources
#model dynamic
#{
ViewBag.Title = "Index";
}
<html>
<head>
<title>Employee Index</title>
<link href="~/Content/Site.css" rel="stylesheet" />
</head>
<body>
<form>
<div id="container">
<!--Bind the TextBoxes in the Table to the observable properties defined into the ViewModel -->
<table id="tblEmployeeView">
<tr>
<td>
<label id="lblFirstName">#Resource.FirstName</label>
</td>
<td>
<input type="text" id="txtFirstName" data-bind="value: $root.FirstName" />
</td>
</tr>
<tr>
<td>
<label id="lblMiddleName">#Resource.MiddleName</label>
</td>
<td>
<input type="text" id="txtMiddleName" data-bind="value: $root.MiddleName" />
</td>
</tr>
<tr>
<td>
<label id="lblNamePrefix">#Resource.NamePrefix</label>
</td>
<td>
<input type="text" id="txtNamePrefix" data-bind="value: $root.Tussenvoegsel" />
</td>
<td>
<label id="lblLastName">#Resource.LastName</label>
</td>
<td>
<input type="text" id="txtLastName" data-bind="value: $root.LastName" />
</td>
</tr>
<tr>
<td>
<label id="lblEmail">#Resource.Email</label>
</td>
<td>
<input type="text" id="txtEmail" data-bind="value: $root.EmployeeEmail" />
</td>
</tr>
<tr>
<td>
<label id="lbPersonalNo">#string.Format("{0} {1}", Resource.Personal, Resource.Number.ToLower())</label>
</td>
<td>
<input type="text" id="txtPersonalNo" data-bind="value: $root.PersonalNumber" />
</td>
</tr>
<tr>
<td>
<label id="lbPhoneNo">#string.Format("{0} {1}", Resource.Phone, Resource.Number.ToLower())</label>
</td>
<td>
<input type="text" id="txtPhoneNo" data-bind="value: $root.PhoneNumber" />
</td>
</tr>
<tr>
<td>
<button data-bind="click: $root.save">Save new</button>
</td>
</tr>
</table>
<div class="Fixed">
<table id="tblEmployees" data-bind="visible: Employees().length>0" style="border: double">
<thead>
<tr>
<td>Full name</td>
</tr>
</thead>
<tbody data-bind="foreach: Employees">
<tr id="objEmployee" data-bind="click: $root.getEmployeeDetails" style="cursor: pointer">
<td><span data-bind="text: $root.FullName"></span></td>
</tr>
</tbody>
</table>
</div>
</div>
</form>
<script src="~/Scripts/jquery-1.11.2.js"></script>
<script src="~/Scripts/knockout-3.0.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.debug.js"></script>
<script src="~/Scripts/ViewScripts/Employee/EmployeeViewModel.js"></script>
</body>
</html>
Here is the code on the controller:
public HttpResponseMessage PostEmployee(Employee employee)
{
// Validate model
if (!ModelState.IsValid) return Request.CreateResponse(HttpStatusCode.BadRequest);
try
{
// Add employee
UoW.Empleyee.Add(employee);
// Save the new employee
UoW.Commit();
// Log change
ApplicationLog.LogChange(new UpdateException("New employee created by userId:" + Globals.Employee.EmployeeId), "Employee id:" + employee.EmployeeId + " created successfully.");
}
catch (Exception ex)
{
// Log error
ApplicationLog.LogError(ex, "UserId:" + Globals.Employee.EmployeeId + " failed adding a new employee.");
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Conflict));
}
// Create response with the new created model
var response = Request.CreateResponse(HttpStatusCode.Created, employee);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = employee.EmployeeId }));
return response;
}
The model is:
public class Employee : EntityBase, IValidatableObject
{
#region Properties
// Self generated field for Id
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EmployeeId { set; get; }
// Company mandatory
[Required]
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
// First name mandatory, max length 75
[Required, StringLength(75)]
public string FirstName { get; set; }
// Middle name not mandatory, max length 75
[StringLength(75)]
public string MiddleName { get; set; }
// Last name mandatory, max length 75
[Required, StringLength(75)]
public string LastName { get; set; }
// Tussenvoegsel (example: van de) not mandatory, max length 15
[StringLength(15)]
public string Tussenvoegsel { get; set; }
// Email addressa mandatory, max length 150
[Required, StringLength(150)]
public string EmployeeEmail { get; set; }
// Object status mandatory
[Required]
public int ObjectStatusId { get; set; }
[ForeignKey("ObjectStatusId")]
public ObjectStatus ObjectStatus { get; set; }
// Enumerable collection for employee details
public virtual ICollection<EmployeeDetails> EmployeeDetailses { get; set; }
#endregion
#region Custom properties
// Full name of employee
public string FullName
{
get
{
// E.g: Andrew, Marteen, de Fulshrad
if (!string.IsNullOrEmpty(MiddleName) && !string.IsNullOrEmpty(Tussenvoegsel))
return string.Format("{0}, {1}, {2} {3}", FirstName, MiddleName, Tussenvoegsel, LastName);
// E.g: Andrew, Marteen, Fulshrad
if (!string.IsNullOrEmpty(MiddleName) && string.IsNullOrEmpty(Tussenvoegsel))
return string.Format("{0}, {1}, {2}", FirstName, MiddleName, LastName);
// E.g: Andrew,de Fulshrad
if (string.IsNullOrEmpty(MiddleName) && !string.IsNullOrEmpty(Tussenvoegsel))
return string.Format("{0}, {1} {2}", FirstName, Tussenvoegsel, LastName);
// E.g: Andrew, Fulshrad
if (string.IsNullOrEmpty(MiddleName) && string.IsNullOrEmpty(Tussenvoegsel))
return string.Format("{0}, {1}", FirstName, LastName);
return null;
}
}
What am i doing wrong?

Found the issue. The model was not parsed properly due to the fact that i forgot about the '[ ]' for the collection
var EmployeeData = {
EmployeeId: self.EmployeeId,
FirstName: self.FirstName,
MiddleName: self.MiddleName,
Tussenvoegsel: self.Tussenvoegsel,
LastName: self.LastName,
FullName: self.FullName,
EmployeeEmail: self.EmployeeEmail,
EmployeeDetailses: [{
PhoneNumber: self.PhoneNumber,
PersonalNumber: self.PersonalNumber
}]
};

Related

Model binding with multiple rows in ASP.NET Core MVC

I've been stuck on this for so long, any help or direction is appreciated.
Basically I want my controller to pass a json data like this:
Initially, I wanted to do it with model binding, but at this moment even jQuery will be fine.
Model class:
public class Orders
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string ItemName { get; set; }
public double Price { get; set; }
public IEnumerable<SelectListItem> CustomersList { get; set; }
}
Controller code:
// GET: OrdersController/Create
public ActionResult Create()
{
var listCustomers = dbContext.Customers
.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.DepName
});
var orders = new Orders()
{
CustomersList = listCustomers
};
//var orders = new List<Orders>();
return View(orders);
}
// POST: OrdersController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(List<Orders> ordersList)
{
Orders newOrders = new Orders();
foreach (var order in ordersList)
{
newOrders.Id = 0;
newOrders.CustomerId = order.CustomerId;
newOrders.ItemName = order.ItemName;
newOrders.Price = order.Price;
}
// I will be processing newOrders into application/json and sending to the backend API
}
View markup:
#model List<NameSpace.Web.Models.Orders>
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="row">
<div class="col-md-8">
<div class="form-group">
#Html.LabelFor(model => model.CustomerId, htmlAttributes: new { #class = "control-label col-md-6" })
#Html.DropDownListFor(model => model.CustomerId, Model.CustomersList, "Select Customer ", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DepId, "", new { #class = "text-danger" })
</div>
</div>
<hr>
<div class="col-md-12">
<div class=''></div>
<thead>
<tr>
//<th style="width:150px">Cust. Id</th>
<th style="width:150px">Item Name</th>
<th style="width:150px">Price</th>
</tr>
</thead>
<tbody id="tblOrdersBody">
<tr>
//<td><input name='Orders[0].CustomerId' class="form-control" /></td>
<td><input name='Orders[0].ItemName' class="form-control" /></td>
<td><input name='Orders[0].Price' class="form-control" /></td>
</tr>
</tbody>
<tfooter>
<tr><a hre="#" class="btn btn-success" id="addOrder"></a> </tr>
</tfooter>
</table>
<div class="row">
<div class="tile-footer d-flex justify-content-around">
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-danger" })
<input id="btnSave" type="submit" value="Save Order" class="btn btn-primary" />
</div>
</div>
</div>
</div>
}
#section Scripts {
<script>
var i = 1;
$(document).on("click", "#addOrder", function () {
$("#tblOrdersBody").append("<tr>"
//+ "<td><input name='Orders[" + i + "].CustomerId' class='form-control' /></td>"
+ "<td><input name='Orders[" + i + "].ItemName' class='form-control'/></td>"
+ "<td><input name='Orders[" + i + "].Price' class='form-control'/></td>"
+ "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
+ "</tr > ");
i++;
});
</script>
}
I have seen many similar questions , the closest one being this one, but I could figure it out, the controller receives 0 in item counts
public ActionResult Create(List ordersList)
You action parameter named ordersList, please try to modify the name attribute of your input(s) on view page, like below.
<tbody id="tblOrdersBody">
<tr>
<td><input name='ordersList[0].CustomerId' class="form-control" /></td>
<td><input name='ordersList[0].ItemName' class="form-control" /></td>
<td><input name='ordersList[0].Price' class="form-control" /></td>
</tr>
</tbody>
JS code
<script>
var i = 1;
$(document).on("click", "#addOrder", function () {
$("#tblOrdersBody").append("<tr>"
+ "<td><input name='ordersList[" + i + "].CustomerId' class='form-control' /></td>"
+ "<td><input name='ordersList[" + i + "].ItemName' class='form-control'/></td>"
+ "<td><input name='ordersList[" + i + "].Price' class='form-control'/></td>"
+ "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
+ "</tr > ");
i++;
});
</script>
Test Result

Mvc 4 model binding not working dynamically added partial view

I am trying to create a form where in user can add controls. I have main view
#model MVCDynamicFormGenerator.Models.FormViewModel
#{
ViewBag.Title = "Create";
}
#using (#Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(form => form.Form.Uid)
#Html.Hidden("ListFields", ViewData["ListFields"])
<p>
#Html.LabelFor(form => form.Form.FormName)
#Html.TextBoxFor(form => form.Form.FormName)
</p>
<div id="FormFieldList">
#foreach (var formfield in Model.FormFields)
{
switch (formfield.ControlType)
{
case ("Textbox"):
Html.RenderPartial("Textbox", formfield);
break;
}
}
</div>
<h4>
[+] Add a Field
</h4>
<div id="FieldType">
<table>
<tr>
<th>
Select a Field Type
</th>
</tr>
<tr>
<td>
#Html.DropDownList("FieldTypes", new SelectList(Model.FormFields[0].FormFieldTypes, "Value", "Text"), new { id = "SelectedFieldUid" })
#Html.ActionLink("Add Field", "NewFormField", new { formId = ViewContext.FormContext.FormId, selectedFieldType = "SelectedFieldUid" }, new { id = "newFormField" })
#Html.ValidationMessageFor(model => model.FormFields)
</td>
</tr>
</table>
</div>
<p>
<input type="submit" value="Create" />
<input type="button" value="Cancel" '#Url.Action("List")');" />
</p>
</fieldset>
}
On dropdown change I am loading a partial view which is working(User can add n number of times)
#model MVCDynamicFormGenerator.Models.FormFieldViewModel
<div class="FormField">
#using (#Html.BeginForm())
{
<table>
<tr>
<th>
Form Field
</th>
<th>
Field Type
</th>
</tr>
<tr>
<td style="width: 45%;">
#Html.TextBoxFor(formfield => formfield.FormFieldName)
#Html.ValidationMessageFor(formfield => formfield.FormFieldName)
</td>
<td style="width: 25%;">
#Html.DropDownListFor(formfield => formfield.SelectedFormFieldType,
new SelectList(Model.FormFieldTypes, "Value", "Text",
Model.SelectedFormFieldType),
new { disabled = "disabled" })
#Html.HiddenFor(formfield => formfield.SelectedFormFieldType)
#Html.ValidationMessageFor(formfield => formfield.SelectedFormFieldType)
</td>
</tr>
</table>
}
</div>
/// form models
public class FormViewModel
{
//Properties
public Form Form { get; set; }
public List<FormFieldViewModel> FormFields { get; set; }
//Constructor
public FormViewModel()
{
Form = new Form();
FormFields = new List<FormFieldViewModel>();
}
}
public class FormFieldViewModel
{
public string FormFieldName { get; set; }
public string SelectedFormFieldType { get; set; }
}
controller methods
[HttpPost]
public ActionResult Create(FormViewModel viewModel)
{
return View();
}
All the field information related to main view gets available but FormFieldViewModel list gives zero count
Any help or suggestion to fix this

MVC4 Get listboxfor Text & Value properties

In My MVC4 EF5 App i'm using 2 listboxes. each listbox is bounded to a List property of my view model.
i would like to get all listboxes items (and i mean all SelectedListItem - Selected, Text, Value) when i submit a from.
This is how i do so (with no sucess..)
My View Model:
public class PriorityViewModel
{
public List<SelectListItem> lst_fromCEID { get; set; }
public List<SelectListItem> lst_C2C { get; set; }
public PriorityViewModel()
{
lst_C2C = new List<SelectListItem>();
lst_fromCEID = new List<SelectListItem>();
}
}
My Action:
public ActionResult Index()
{
var model = new PriorityViewModel();
var c2c_ceid_source = _unitOfWork.ActionRepository.GetC2C_SourceCEID();
model.lst_fromCEID = _unitOfWork.EntityRepository.GetEntitiesByC2CSource(c2c_ceid_source);
return View(model);
}
public ActionResult UpdatePriority(PriorityViewModel model)
{
//save manual changes to DB
SaveManualPriorityToDB(model);
...
}
My View:
#model TRM.Models.ViewModel.PriorityViewModel
#{
ViewBag.Title = "Index";
}
#*#Html.Action("Run");*#
#using (Html.BeginForm("UpdatePriority", "Priority", FormMethod.Post))
{
#Html.Hidden("demoQuantity", Model.demoQuantity)
#Html.Hidden("installQuantity", Model.installQuantity)
#Html.Hidden("CIP_Quantity", Model.CIP_Quantity)
#Html.Hidden("C2C_Quantity", Model.C2C_Quantity)
<table>
<tr>
<td>
From CEID
#Html.ListBoxFor(model => model.lst_fromCEID, #Model.lst_fromCEID, new { width = "50px" })
</td>
<td style="width:50px">
<input id="btnRemoveAllC2C" type="button" value=" << " onclick="removeallItemsC2C();" />
<input id="btnAddAllC2C" type="button" value=" >> " onclick="addallItemsC2C();" />
<input id="btnAddC2C" type="button" value=" > " onclick="addItemC2C();" />
<input id="btnRemoveC2C" type="button" value=" < " onclick="removeItemC2C();" />
</td>
<td style="width:50px">
C2C
#Html.ListBoxFor(model => model.lst_C2C, new MultiSelectList(Model.lst_C2C), new { width = "50px" })
</td>
</tr>
<tr>
<td>
<h2>Install & Orphan</h2>
</td>
</tr>
</table>
<input type="submit" value="Run Transition!" onclick="SelectAllItems()"/>
}
#section scripts {
<script src="~/Scripts/MyScripts/PriorityScript.js"></script>
}
My Js File:
function addItemC2C() {
$("#lst_fromCEID option:selected").appendTo("#lst_C2C");
$("#lst_C2C option").attr("selected", false);
}
function addallItemsC2C() {
$("#lst_fromCEID option").appendTo("#lst_C2C");
$("#lst_C2C option").attr("selected", false);
}
function removeItemC2C() {
$("#lst_C2C option:selected").appendTo("#lst_fromCEID");
$("#lst_fromCEID option").attr("selected", false);
}
function removeallItemsC2C() {
$("#lst_C2C option").appendTo("#lst_fromCEID");
$("#lst_fromCEID option").attr("selected", false);
}
if i set the viewModel properties to List i can get the listbox text out on button submit. but this is not enough for me, i need Text and Value.
Thx..

My list will be empty when POST the form

I have some problem with the MVC, I'll try to describe. I have 2 class in my model.
public class ApplicationPermissionVM
{
public ApplicationPermission Permission { get; set; }
public bool IsSelected { get; set; }
}
public class RoleAndPermissonsModel
{
//Constructor skipped
public ApplicationRole ApplicationRole { get; set; }
public IEnumerable<ApplicationPermissionVM> Permissions { get; set; }
}
The second model is the main model, and I initialize the model in controller. The ApplicationRole is null and I have got 19 element in the list. When I POST the form the ApplicationRole member will be created, but the Permissions list will be empty so will lost all selection. If anyone knows what is the problem please write to me.
Controller:
[HttpGet]
public ActionResult NewRole()
{
_model = new RoleAndPermissonsModel();
return View(_model);
}
[HttpPost]
public ActionResult NewRole(RoleAndPermissonsModel newRole)
{
if (ModelState.IsValid)
{
var id = _applicationRoleService.AddNewRole(newRole.ApplicationRole);
_applicationRoleService.AssignPermissionsToRole(newRole.SelectedItems, id);
}
return RedirectToAction("Index");
}
View:
#model EO.Core.WebUI.Models.RoleAndPermissonsModel
#using (Html.BeginForm("NewRole", "PermissionRole", FormMethod.Post, new { id = "frmNewRole" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ApplicationRole</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ApplicationRole.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ApplicationRole.Name)
#Html.ValidationMessageFor(model => model.ApplicationRole.Name)
</div>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.IsSelected)
</th>
<th></th>
</tr>
#foreach (var item in Model.Permissions)
{
<tr>
<td>
#Html.EditorFor(modelItem => item.IsSelected)
</td>
<td>
#Html.DisplayFor(modelItem => item.Permission.Name);
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
you need manually to loop through the list and output it like
<input type="text"
id="Permissions[0].IsSelected"
name="Permissions[0].IsSelected" value="" />
so, change your code to:
#for(int i = 0; i < Model.Permissions.Count; i++)
{
<tr>
<td><input type="checkbox"
id="Permissions[#(i)].IsSelected"
name="Permissions[#(i)].IsSelected" /></td>
<td><input type="text"
id="Permissions[#(i)].Permission.Name"
name="Permissions[#(i)].Permission.Name" /></td>
</tr>
}
because you have an object inside your type Permissions remember to initialiate it or you will get a null reference.
public class RoleAndPermissonsModel
{
public RoleAndPermissonsModel() {
this.Permissions = new List<ApplicationPermissionVM>();
}
public ApplicationRole ApplicationRole { get; set; }
public IEnumerable<ApplicationPermissionVM> Permissions { get; set; }
}
or you can easily create a ViewModel instead and use that to interlink your Model to your View.
Note: I do wonder, if your list is always null (as you are passing an empty/null list) why are you looping through Model.Permissions ?
In order to do the "EDIT" view, the loop code should be:
#for(int i = 0; i < Model.Permissions.Count; i++)
{
<tr>
<td><input type="checkbox"
#(Permissions[i].IsSelected ? "checked='checked'" : "")
id="Permissions[#(i)].IsSelected"
name="Permissions[#(i)].IsSelected" /></td>
<td><input type="text"
id="Permissions[#(i)].Permission.Name"
name="Permissions[#(i)].Permission.Name"
value="#(Permissions[i].Permission.Name)" /></td>
</tr>
}
all you need to add is checked to the checkbox if it's selected and fill the permission name to the other input.

knockoutjs and jquery UI slider

I have list collection like:
{Id : "101", Name :"XXX", Fare: 200 },
{Id : "102", Name :"YYY", Fare: 400 },
{Id : "103", Name :"ZZZ", Fare: 500 },
Now I want to implement Jquery UI slider in knockoutJs with min and maximum fare, based on it I will filter my list.
How I can pass min and max value from observable array min and max fare to Slider using knockoutjs?
Updated with Code:
Html
<div class="row">
<div class="span3 well">
<h4>Filter</h4>
<hr />
<div>
<strong>Fare Range</strong>
<br />
Rs <span id="minFare" data-bind="text : minFare" ></span>
- Rs
<span id="maxFare" data-bind="text : maxFare" ></span>
<div id="slider-range"></div>
</div>
<hr />
<div>
<strong >Bus Type</strong>
<ul data-bind="foreach : busTypes">
<li>
<input type="checkbox" > <span data-bind="text : $data"></span>
</li>
</ul>
</div>
</div>
<div class="span9">
<div class="well">
<strong>Sort </strong>
<div data-bind="foreach: sortingColumns" class="btn-group inline " data-toggle="buttons-checkbox">
<div class="btn" data-bind="text : columnName, click : $root.sort">
</div>
</div>
</div>
<section id="no-more-tables">
<table class="table-bordered table-striped table-condensed cf">
<thead class="cf">
<tr>
<th>
Travel
</th>
<th>
Deparr
</th>
<th>
Arrive
</th>
<th class="numeric">
Seat
</th>
<th class="numeric">
Fare
</th>
</tr>
</thead>
<tbody data-bind="foreach: busResults">
<tr>
<td data-bind="text: CompanyName" data-title="Travel">
</td>
<td data-bind="text: DepartureTime" data-title="Depart">
</td>
<td data-bind="text: ArrivalTime" data-title="Arrive">
</td>
<td data-bind="text: Seats" data-title="Seat" class="numeric">
</td>
<td data-bind="text: Fare" data-title="Fare" class="numeric">
</td>
<td>
<a class="btn btn-info" href="#" >Select</a>
</td>
</tr>
</tbody>
</table>
</section>
</div>
</div>
Js
$(function () {
$("#slider-range").slider({
range: true,
min: $("#minFare").text(),
max: $("#maxFare").text(),
values: [75, 300],
slide: function (event, ui) {
$("#minFare").text(ui.values[0]);
$("#maxFare").text(ui.values[1]);
//$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);
}
});
//$("#amount").val("$" + $("#slider-range").slider("values", 0) +
//" - $" + $("#slider-range").slider("values", 1));
});
knockoutjs ViewModel
function busResultsViewModel(param) {
var self = this;
var baseUri = "/api/BusApi/" + param;
self.busResults = ko.observableArray();
self.currentItem = ko.observable('');
self.sortDirection = ko.observable(false);
//Sort By Name
self.sort = function (item) {
var colName = item.columnName == "Travel" ? "CompanyName" : item.columnName;
self.sortDirection(!self.sortDirection());
var test = self.busResults.sort(function (obj1, obj2) {
if (obj1[colName] == obj2[colName]) return 0;
else if (obj1[colName] < obj2[colName])
return -1;
else
return 1;
});
if (self.sortDirection())
self.busResults(test);
else
self.busResults(test.reverse());
};
//Min/Max Fare // Tried
self.minFare = ko.dependentObservable(function () {
var min = 0;
ko.utils.arrayForEach(self.busResults, function (item) {
alert(item.Fare);
if (item.Fare < min) {
min = item.Fare;
}
});
return min;
} );
self.minFare = ko.observable("0");
self.maxFare = ko.observable("800");
self.busTypes = ko.observableArray(["AC", "Non-AC"]);
//Sorting Coumns
self.sortingColumns = ko.observableArray([
{ columnName: "Travel" },
{ columnName: "Fare" }
]);
$.getJSON(baseUri, self.busResults);
}
Model Structure
public class BusResult
{
public int Id { get; set; }
public string CompanyName { get; set; }
public string DepartureDate { get; set; }
public string DepartureTime { get; set; }
public string ArrivalDate { get; set; }
public string ArrivalTime { get; set; }
public string Amenities { get; set; }
public short JourneyHours { get; set; }
public short Seats { get; set; }
public decimal Fare { get; set; }
public IList<string> BusTypes {get; set;}
}
Finally got working:
Html
<span id="minFare" data-bind="text : minFare"></span> - Rs
<span id="maxFare" data-bind="text : maxFare"></span>
<div id="slider-range"></div>
Js
Slider
$("#slider-range").slider({
range: true,
min: vm.minFare(),
max: vm.maxFare(),
step: 1,
values: [vm.minFare(), vm.maxFare()],
slide: function (event, ui) {
vm.minFare(ui.values[0]);
vm.maxFare(ui.values[1]);
}
});
Vm
//Min & Max Slider
function vm()
{
var self = this;
self.minFare = ko.observable();
self.minFare.subscribe(function (newValue) {
//TODO: Filter, min fare changed
});
self.maxFare = ko.observable();
self.maxFare.subscribe(function (newValue) {
//TODO: Filter, max fare changed
});
}