how to bind selectlist to value using json in javascript - javascript

I'm new to web application development and i need to bind values which i retrieved from json object. i tried several ways but couldn't able to bind values to my combo box.
<script type="text/javascript">
var ViewModel = {
CheckIn : ko.observable(),
CheckOut: ko.observable(),
Lunch: ko.observable(),
Rest: ko.observable(),
WorkOnProject: ko.observable(),
Projects: ko.observableArray()
};
this.GetProjects = function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
var value = arg.d[i].ProjectCode;
var option = new Option(arg.d[i].ProjectCode, arg.d[i].ProjectCode);
Select1.add(option, null);
}
},
error: function (arg) {
}
});
};
ko.applyBindings(ViewModel);
</script>
My HTML Code:
<tr>
<td class="auto-style1">Project Code </td>
<td ><select id="Select1" data-bind='options: Projects' style="width: 312px"></select>
<button data-bind='click: GetProjects'>Cancel</button>
</td>
</tr>
My Sever Side Coding :
[WebMethod]
public static object ReturnComplexType()
{
List<Project> projects = new List<Project>();
Project p = new Project();
p.ProjectID = 1;
p.ProjectCode = "ABC";
p.ProjectName = "Test";
projects.Add(p);
Project p2 = new Project();
p2.ProjectID = 2;
p2.ProjectCode = "DEF";
p2.ProjectName = "xsd";
projects.Add(p2);
return projects;
}

Your structure is way off, you're mixing object instances with function on the window object..
This is one way of solving it
ViewModel = function() {
this.CheckIn = ko.observable();
this.CheckOut = ko.observable();
this.Lunch = ko.observable();
this.Rest = ko.observable();
this.WorkOnProject = ko.observable();
this.Projects = ko.observableArray()
};
ViewModel.prototype = {
GetProjects: function () {
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
this.Projects(data);
}.bind(this),
error: function (arg) {
}
});
};
};
ko.applyBindings(new ViewModel());
What I did was to move the GetProjects function to the model object

Your select box is bound to the Projects observable but you don't set an explicit text/value
<select id="Select1" data-bind='options: Projects, optionsText: 'ProjectName', optionsValue:'ProjectID', value: SelectedProjectId"' style="width: 312px"></select>
The SelectedProjectId would be another observable in your model if you need to save the value somewhere.
The other thing you'll want to change is filling the actual observable array instead of select box directly.
<script type="text/javascript">
function ViewModel() {
var self = this;
self.CheckIn = ko.observable();
self.CheckOut = ko.observable();
self.Lunch = ko.observable();
self.Rest = ko.observable();
self.WorkOnProject = ko.observable();
self.Projects = ko.observableArray();
};
var VM = new ViewModel();
ko.applyBindings(ViewModel);
$.ajax({
type: "POST",
url: 'TimeRecord.aspx/ReturnComplexType',
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (arg) {
for (var i = 0; i < arg.d.length ; i++) {
VM.Projects.push(d[i]);
}
},
error: function (arg) {
}
});
</script>
After you get things binding right you'll probably want to swap out the VM.Projects.push() for a speedier way.
Calling .push() when you're filling up arrays on initial load triggers a ton of notifications that can really make the page crawl.

Related

500 error with knockout delete

I am getting a 500 error when I try and delete an item in my list using ajax.
From using the console on Chrome combined with Fiddler, a null reference on the Id is the issue. Debugging through Chrome's console shows that the announcement object does have an Id.
I was under the impression 500 errors came from the server, but I have a break point on the function path it's calling and not getting hit.
Is there anything that is staring me in the face as to why this would be setting the announcement.Id to null?
controller:
public JsonResult DeleteAnnouncement(int Id)
{
if(repository.DeleteAnnouncement(Id))
{
return Json(repository.GetAllAnnouncements(), JsonRequestBehavior.AllowGet);
}
return Json(null);
}
repository:
public bool DeleteAnnouncement(int Id)
{
var model = (from a in db.DbAnnouncement
where a.Id == Id
select a).SingleOrDefault();
if (model.Id != 0)
{
db.DbAnnouncement.Remove(model);
db.SaveChanges();
return true;
}
else
{
return false;
}
}
js script:
<script type="text/javascript">
function AnnouncementViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Title = ko.observable("");
self.Details = ko.observable("");
self.DTCreated = ko.observable("");
self.LastUpdated = ko.observable("");
self.CreatedUser = ko.observable("");
self.UpdatedUser = ko.observable("");
self.VersionNum = ko.observable("");
self.StartDT = ko.observable("");
self.ExpiryDT = ko.observable("");
self.Enabled = ko.observable("");
self.GroupID = ko.observable("");
self.URLLink = ko.observable("");
var Announcement = {
Id: self.Id,
Title: self.Title,
Details: self.Details,
DTCreated: self.DTCreated,
LastUpdated: self.LastUpdated,
CreatedUser: self.CreatedUser,
UpdatedUser: self.UpdatedUser,
VersionNum: self.VersionNum,
StartDT: self.StartDT,
ExpiryDT: self.ExpiryDT,
Enabled: self.Enabled,
GroupID: self.GroupID,
URLLink: self.URLLink
};
self.Announcement = ko.observable();
self.Announcements = ko.observableArray(); // list of announcements
// Delete announcement
self.delete = function (Announcement) {
if (confirm('Are you sure to Delete "' + Announcement.Title + '"?')) {
$.ajax({
url: '#Url.Action("DeleteAnnouncement","Announcement")',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
//data: ko.toJSON(Announcement.Id),
data: {Id: Announcement.Id},
success: function (data) {
self.Announcements.remove(Announcement);
alert("Record Deleted Successfully");
}
}).fail(
function (xhr, textStatus, err) {
alert(err);
});
}
}
}
$(document).ready(function () {
var viewModel = new AnnouncementViewModel();
ko.applyBindings(viewModel);
});
You are using ajax contentType as Json but not really sending a json object to server. Use
data: JSON.stringify({ Id: Announcement.Id() }),
and decorate your mvc action with [HttpPost]
[HttpPost]
public JsonResult DeleteAnnouncement(int Id)
{}

putting condition on self.load function in knockout

This is my view model:
function viewModel() {
var self = this;
self.posts = ko.observableArray();
self.newMessage = ko.observable();
self.error = ko.observable();
and these are my two loads functions:
self.reloadPosts = function () {
$.ajax({
type: "Get",
url: postApiUrl2,
data: { id: $("#Locations").val() },
datatype: "json",
contentType: "application/json"
})
}
self.loadPosts = function () {
// to load existing posts
$.ajax({
url: postApiUrl1,
// data: { id: $("#Locations").val() },
datatype: "json",
contentType: "application/json",
cache: false,
type: 'Get'
})
}
self.loadPosts();
self.reloadPosts();
return self;
here, self.loadPosts is the function with no parameter in it and self.reloadPosts passes selected dropdown id to controller.
My question is-- is it possible to put condition here so that self.reloadPosts should only load data on the view page when it has some data.
Right now, both of these are loading one by one. i want to control it by some condition.this code is in .js file not on .cshtml page.
I am trying something like this but getting uncaught reference errror at first line:
if (id != null) {
self.reloadPosts();
}
else {
self.loadPosts();
}
Can anyone suggest me something how to do it.
I don't know what #locations refers to, but if it's a select list or something try this in the HTML (for example):
<select data-bind="value: locations">
<option>location 1</option>
<option>location 2</option>
<select>
And change the script:
function viewModel() {
var self = this;
// location will be stored here
self.locations = ko.observable();
self.posts = ko.observableArray();
self.newMessage = ko.observable();
self.error = ko.observable();
// we can avoid some repeat code:
self.loadPosts = function () {
// read value
var id = self.locations();
// set url and data
var url = (id) ? postApiUrl2 : postApiUrl1;
var data = (id) ? { id: id } : null;
$.ajax({
type: "Get",
url: url,
data: data,
datatype: "json",
contentType: "application/json"
})
}
self.loadPosts();
return self;
Hope this helps.

Knockoutjs bind an observableArray to byte

I am trying to bind an array of values from a check box list to a model that has a property type of byte. So I am returned {"1", "2" , "3"} from check box selections I am needing this in byte format before it reaches my model so it can be passed properly to my model.
Property byte { get; set; }
My Knockout Viewmodel where self.DaysList = ko.observableArray(); is my check box list property.
function ScheduledCommand() {
//data
var self = this;
// An observable is a “JavaScript object that can notify subscribers about changes.”
// When the contents of an observable change, the view is automatically updated to match.
self.ScheduledCommandId = ko.observable();
self.NextOccurence = ko.observable();
self.CommandType = ko.observable();
self.CommandAssembly = ko.observable();
self.IntervalAmount = ko.observable();
self.IntervalType = ko.observable();
self.Catchup = ko.observable();
self.Retry = ko.observable();
self.SendToQueue = ko.observable();
self.Enabled = ko.observable();
self.SelectedCommand = ko.observable();
self.DaysList = ko.observableArray();
var Command = {
ScheduledCommandId: self.ScheduledCommandId,
NextOccurence: self.NextOccurence,
CommandType: self.CommandType,
CommandAssembly: self.CommandAssembly,
IntervalAmount: self.IntervalAmount,
IntervalType: self.IntervalType,
Catchup: self.Catchup,
Retry: self.Retry,
SendToQueue: self.SendToQueue,
Enabled: self.Enabled,
SelectedCommand: ko.observable(),
DaysList: ko.observableArray(),
};
self.Command = ko.observable();
self.Commands = ko.observableArray();
self.get = function () {
$.ajax({
url: '/api/Values',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Commands(data); //Put the response in ObservableArray
$("#btnGetCommands").hide();
$("#commandlist").show();
$("#btnHideCommands").show();
}
});
}
self.hidecommands = function ()
{
$("#btnGetCommands").show();
$("#btnHideCommands").hide();
$("#commandlist").hide();
}
//ko.bindingHandlers.bootstrapPopover = {
// init: function (element, valueAccessor, allBindingsAccessor, Command) {
// var options = valueAccessor();
// var defaultOptions = {};
// options = $.extend(true, {}, defaultOptions, options);
// $(element).popover(options);
// }
//};
self.create = function (formElement) {
if (Command.NextOccurence() != "" && Command.CommandType() != "" && Command.CommandAssembly() != "") {
$.ajax({
url: '/api/Values',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Command),
success: function (data) {
// alert('added');
self.Commands.push(data);
self.DaysList("");
self.NextOccurence("");
self.CommandType("");
self.CommandAssembly("");
self.IntervalAmount("");
self.IntervalType("");
self.Catchup("");
self.Retry("");
self.SendToQueue("");
self.Enabled("");
alert("Command " + self.CommandType() + " successfully created.")
}
}).fail(
function (xhr, textStatus, err) {
alert(err);
});
}
else {
alert('Please Enter All the Values !!');
}
},
self.selectCommand = function (command) {
self.SelectedCommand(command.ScheduledCommandId)
alert(command.ScheduledCommandId);
},
document.getElementById("btnGetCommands").onclick
}
$(document).ready(function () {
// When the DOM is fulled loaded, call the ko.applyBindings function and pass
// in a new instance of the commandViewModel:
$("#btnHideCommands").hide();
$("#commandlist").hide();
ko.applyBindings(new ScheduledCommand());
// The ko.applyBindings method activates Knockout and wires up the view-model to the view.
});
My API Controller Method this has no value for DaysList
public HttpResponseMessage Post(ScheduledCommand model)
{
repo.Add(model);
var response = Request.CreateResponse<ScheduledCommand>(HttpStatusCode.Created, model);
string uri = Url.Link("DefaultApi", new { id = model.ScheduledCommandId });
response.Headers.Location = new Uri(uri);
return response;
}
Finally my check box list.
#foreach (var item in ViewData["checklist"] as IEnumerable<SelectListItem>)
{
<div class="checkbox">
<label>
<input type="checkbox" data-bind="attr: { value: #item.Value}, checked: $root.DaysOfWeek">
#item.Text
</label>
</div>
}
The Knockout side of it is good it returns what I want but I can not convert it to a byte.
Thank you for your time!
What I wanted to do was try to convert a knockout observable array to a byte before it was passed to server in order to satisfy the parameter type(small int). Instead, what I did was create a "placeholder"(string array) property and convert it to a byte to satisfy my data property.
I was just hoping to remove the additional step using javascript.

Knockout.js : manually trigger computed

I have a grid and a select control on the page. Choosing any select value triggers grid update. That updating is done using computed. Can I manually trigger grid to update, say, in situation when a new value is added to a grid?
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.pager = {
page_namber : ko.observable(1),
page_size : ko.observable(10)
};
self.sort = {
field : ko.observable('name'),
dist : ko.observable('asc')
};
// etc.
self.fetch = ko.computed(function(){
$.ajax({
url: '/api/items/',
type: 'GET',
data: ko.toJSON(self),
contentType: 'application/json',
success: self.items
});
}, self);
self.add_item = function() {
//here I want to update the grid
self.fetch(); // not work
};
}
Sure I can move it to a separate function but I am looking for a cleaner solution.
Thanks!
working version :
function vm() {
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("test");
self.pager = {
page: ko.observable(1),
size: ko.observable(10)
};
self.sort = {
field: ko.observable('name'),
dist: ko.observable('asc')
};
self.fetch = function () {
var data = {
category: self.chosen_category(),
pager: ko.toJS(self.pager),
sort: ko.toJS(self.sort)
};
$.ajax({
url: '/api/items/',
type: 'POST',
data: ko.toJSON(data),
contentType: 'application/json',
success: self.items
});
};
self._auto_update = ko.computed(self.fetch).extend({ throttle: 1 }); ;
self.add_item = function () {
self.fetch();
};
}
It is better to do this with subscription instead of computed. In that case you can define fetch function to use for both subscription and manual call:
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.fetch = function(){
$.get('/api/items/' + self.chosen_category(), self.items);
};
self.chosen_category.subscribe(self.fetch);
self.add_item = function() {
//here I want to update the grid
self.fetch();
};
}
Also you can do the same with computed:
function vm(){
var self = this;
self.items = ko.observableArray([]);
self.chosen_category = ko.observable("");
self.fetch = function(){
$.get('/api/items/' + self.chosen_category(), self.items);
};
self.doStaff = ko.computed(self.fetch);
self.add_item = function() {
//here I want to update the grid
self.fetch();
};
}

KnockoutJS race condition during ajax call

Here is a weird race condition happening with knockoutjs. I'm setting two observables independantly using ajax calls. One is a list, the other is a single value. The weird thing is when I load the single value before the list, it won't bind correctly. Any suggestions?
JsFiddle: http://jsfiddle.net/JasonMore/bxfXd/110/
View
<form data-bind='submit:addItem'>
Add item: <input data-bind='value:itemToAdd, valueUpdate: "afterkeydown"' type='text' />
<button data-bind='enable: isAddButtonEnabled' type='submit'>Add</button>
</form>
<p>Your values:</p>
<select data-bind='options:allItems, value:selectedItems' height='5'> </select>
<div>
<button data-bind='click: removeSelected'>Remove</button>
<button data-bind='click: function() { allItems.sort() }, enable: allItems().length > 1'>Sort</button>
</div>
</div>
Code
var betterListModel = function() {
var self = this;
// properties
this.itemToAdd = new ko.observable("");
this.allItems = new ko.observableArray();
this.selectedItems = new ko.observable('');
// computed
this.isAddButtonEnabled = ko.computed(function() {
return self.itemToAdd().length > 0
});
//methods
this.addItem = function() {
if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) this.allItems.push(this.itemToAdd());
this.itemToAdd("");
}
this.removeSelected = function() {
this.allItems.removeAll(this.selectedItems());
this.selectedItems();
} };
var view = new betterListModel();
ko.applyBindings(view);
// load $.ajax({
url: '/echo/json/',
type: 'post',
data: {
json: $.toJSON("Ham"),
delay: 1
},
success: function(data) {
view.selectedItems(data);
} });
$.ajax({
url: '/echo/json/',
type: 'post',
data: {
json: $.toJSON(["Fries", "Eggs Benedict", "Ham", "Cheese"]),
delay: 2
},
success: function(data) {
$.each(data, function(index, value) {
view.allItems.push(value);
});
} });
Try this-->
// Whenever the states changes, reset the selectedState selection
this.allItems.subscribe(function () {
this.selectedItems(arrayOfMySelectedItems);
});

Categories