Sending knockout viewmodel to controller is missing items from drop down box - c#

Little by little I'm learning this...
In my C#/MVC4 demo build I've created a controller to send data to my view through JSON. In my view I am able to parse the response and populate a drop down list.
I'm using knockout similar to a cart to create additional lines (colors) for posting to the controller.
code:
MVC ViewModel:
function Color(data) {
this.ID = ko.observable(data.ID);
this.ColorName = ko.observable(data.ColorName);
this.Duration = ko.observable(data.Duration);
this.bNotPermanent = ko.observable(1);
}
function ViewModel() {
self = this;
self.CurrentColors = ko.observableArray([]);
self.AddColors = ko.observableArray([]);
self.AllColors = ko.observableArray([]);
$.ajax({
type: "POST",
url: '#Url.Action("GetUsersColors", "EditUser")',
data: { szUserRecID: RecID },
success: function (data) {
var colors = $.map(data, function (item) {
return new Color(item)
});
self.CurrentColors(colors);
},
error: function (err) {
alert(err.status + " : " + err.statusText);
}
})
$.ajax({
type: "POST",
url: '#Url.Action("GetVisibleColors", "EditColor")',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: {},
success: function (data) {
var colors = $.map(data, function (item) {
return new Color(item)
});
self.AllColors(colors);
},
error: function (err) {
alert(err.status + " - " + err.statusText);
}
})
self.removeLine = function (color) { self.AddColors.remove(color);
};
self.addColor = function (color) {
self.AddColors.push(new Color({ ColorName: "", ID: "", Duration: "Permanent" }))
};
self.save = function ()
{
// I've also tried data: ko.mapping.toJSON(this)
// based on my issues I've seen, I'm almost positive this is where my issue is
// I think the mapping is having an issue but I don't know what it should look like
// with an array of objects
$.ajax({
url: '#Url.Action("PostColors", "EditColor")',
type: "POST",
data: ko.mapping.toJSON(this.AddColors()),
async: true,
contentType: "application/json"
}).success(function (data) {
});
};
this does work...
View
<table>
<thead>
<tr data-bind =" visible: $root.AddColors().length > 0">
<th padding: 10px; >Color</th>
<!--<th padding: 10px; >Duration</th>-->
</tr>
</thead>
<tbody data-bind="foreach: AddColors">
<tr>
<!-- This works, it displays all the colors provided by the controller -->
<td><select data-bind="options: $root.AllColors, optionsText: 'ColorName', value: ID, optionsCaption: 'Select Color...'"></select></td>
<td>
<a href='#' data-bind='click: $parent.removeLine'>Remove</a>
</td>
</tr>
</tbody>
</table>
<button data-bind='click: addColor'>Add Color</button>
<button data-bind='click: save'>Submit Colors</button>
controller:
[HttpPost]
public void PostColors(List<ViewModels.ColorList> AddColors)
{
int t = 0; // to set a break point only
}
C# ViewModel
public class ColorList
{
public int? ID { get; set; }
public string ColorName { get; set; }
public string Duration{ get; set; }
public bool bNotPermanent { get; set; }
}
when I inspect AddColors in the above function, the Duration is set but the ColorName is null but I do have the correct number of elements coming through.
I can add lines(colors) over and over on the form and selecting them on the list. But why are they not showing in "AddColors" object list?
I did find another article on here referring to get; set; in the viewmodel and I did add that. Up until that point everything coming through was null.
Fiddler is showing this (and it doesn't look quite right...?)
[{"ID": {"ID":11,"ColorName":"Green","Duration":null,"bNotPermanent":1},"ColorName":"","Duration":"Permanent","bNotPermanent":1},{"ID": {"ID":17,"ColorName":"Red","Duration":null,"bNotPermanent":1},"ColorName":"","Duration":"Permanent","bNotPermanent":1}]
I really think my issue is with the data conversion / ajax post. Question is, what should it look like?

I'm guessing that you want the ID of the color to appear in the ID field on the added color entry. If so, what you need to do is that you need to set the optionsValue binding to select a single property from the selected item and use the value of that property to set the property you are binding to.
The Knockout documentation on the options binding states the following regarding the optionsValue binding.
Similar to optionsText, you can also pass an additional parameter called optionsValue to specify which of the objects’ properties should be used to set the value attribute on the elements that KO generates.
Since you don't want the whole object to be set into the ID property of your added color, you want Knockout to pick the ID property from the color. So just update your binding from:
<select data-bind="options: $root.AllColors,
optionsText: 'ColorName',
value: ID,
optionsCaption: 'Select Color...'">
</select>
to:
<select data-bind="options: $root.AllColors,
optionsText: 'ColorName',
optionsValue: ID,
value: ID,
optionsCaption: 'Select Color...'">
</select>

Related

Pass Model and Variables with AJAX

A partial view (_AddItem.cshtml) is called from the main view (Category.cshtml) in order to add existing items to the page on load.
I'm now adding AJAX so that an item can be added, to the page, by the user at the click of a button. When the form is subsequently submitted the item will be added to the model.
The partial view relies on the category model (activeCategoryModel) and two variables. Currently, these are successfully being passed from the view in the following way:
Category.cshtml
#Html.Partial(
"_AddItem",
activeCategoryModel,
new ViewDataDictionary(ViewData) { { "itemIndex", itemIndex }, { "itemLabel", itemLabel } }
);
My question is how can I pass the model (activeCategory) and these two variables when using AJAX? Below is the code I've started writing for the AJAX post:
Button and inputs added to view (Category.cshtml)
<input id="add-item-label" type="text" />
<input id="nextItemIndex" type="hidden" value="#activeCategoryModel.Items.Count" />
<button id="add-item" type="button">Add Item</button>
AJAX post added in javascript
This is not necessary fully functional code, I've just attempted to write an AJAX post with the variables in the 'data' parameter.
$("#add-item").click(function () {
var itemIndex = $("#nextItemIndex").val();
var itemLabel = $("#add-item-label").val();
$.ajax({
type: "POST",
url: '#Url.Action("_AddItem")',
data: '{{itemIndex: ' + itemIndex + '}, {itemLabel: ' + itemLabel + '}}',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
$("#nextItemIndex").val($("#nextItemIndex").val() + 1);
},
error: function () {
alert("Error while adding item");
}
});
return false;
});
Partial view call added to Controller
I think this is where the model and variables need to be included in the partial view call.
public ActionResult _AddItem(string itemIndex, string itemLabel)
{
return PartialView();
}
Partial View (_AddItem.cshtml)
This has not been changed for the AJAX post.
#model CategoryModel
#{ int i = (int)ViewData["itemIndex"];}
#{ string l = (string)ViewData["itemLabel"];}
...
There are different ways in this case,
Example : Html.RenderPartial directly rendered partial action without ajax.
If you want to use Ajax to call partialView , you must be render
Html. Because PartialView returned Html.
I think the most important value in Ajax request is dataType and
the second important point is added returned html data in a div element
jQuery("#add-item").click(function () {
var dItemIndex = 1; //$("#nextItemIndex").val();
var dItemLabel = "Text"; // $("#add-item-label").val();
$.ajax({
type: "POST",
url: '#Url.Action("_AddItem","Home")',
data: { itemIndex: dItemIndex, itemLabel: dItemLabel },
dataType: "html",
//contentType: "application/json; charset=utf-8",
success: function (d) {
console.log("Success");
$("#partialData").html(d);
**// Create div in cshtml Page
// <div id="partialData"></div>**
},
error: function () {
alert("Error while adding item");
}
});
return false;
});
At the controller side you can read parameters and fill in the content and send the PartialView as follows.
public ActionResult _AddItem(string itemIndex, string itemLabel)
{
ViewData["itemIndex"] = itemIndex;
ViewData["itemLabel"] = itemLabel;
return PartialView(new CategoryModel { Id = 5, Text = "Sample 5" });
}

How to implement select2.js c# ajax call is not working

Hello I want to load country state and city using select2.js how can i achieve this? i make ajax call to load details of country state and city... i am facing problem when trying to make ajax call to load data using webmethod. BindCountryData and BidnStateData are never called please suggest me solution for that what changes should i do to make call.
$(document).ready(function){
country();
}
function country(){
$(".autosuggest").select2({
minimumInputLength: 1,
placeholder: "Select Item",
allowClear: true,
ajax: {
type: "POST",
url: 'country.aspx/BindCountryData',
async : false,
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: function(term) {
return {
country: term
};
},
results: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.completeName,
slug: item.slug,
id: item.id
}})};}}});}}
$('.autosuggest').change(function () {
searchState();
});
function searchState(){
$(".State").select2({
minimumInputLength: 1,
placeholder: "Select State",
allowClear: true,
ajax: {
type: "POST",
url: 'state.aspx/BidnStateData',
async : false,
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: function(term) {
return {
state: term,
countryId : $('.autosuggest').val()
};
},
results: function (data) {
return {
results: $.map(data, function (item) {
return {
text: item.completeName,
slug: item.slug,
id: item.id
}
})
};
}
}
});
}}
I've been using the following approach in my projects:
1) Load select elements at initial stage, and bind onChange action:
<select class="selectcombusca" name="zone_id" onChange="carregacidades($('option:selected',this).val());">
<option value="#">Select State</option>
<option value="1">State 1</option>
<option value="2">State 2</option>
</select>
<select class="selectcombusca" name="cidade_id">
<option value="#">Select City</option>
<option value="1">City 1</option>
<option value="2">City 2</option>
</select>
2) Apply select2 to initial elements:
$(".selectcombusca").select2();
3) Function to load cities based on the selected state, triggered on the select change:
function carregacidades(zone_id) {
$.ajax({
url: your-url,
type: 'post',
dataType: 'json',
data: 'zone_id=' + zone_id, //from the selected option
beforeSend: function() {
$('select[name=\'cidade_id\']').hide();
$('select[name=\'cidade_id\'] + .select2').hide();
//I like to hide the inital element so the user can undestand there's a call being made, avoiding multiple changes on the element.
$('select[name=\'cidade_id\']').after('<span class="loading">Loading Indicator<span>'); //I also like to put some kind of loading indicator, like a spinner
},
complete: function() {
$('.loading').remove(); //remove the loading indicator
$('select[name=\'cidade_id\']').show(); //show DOM element
$("select[name=\'cidade_id\']").select2().val('#'); //rerender select2 and set initial option
$('select[name=\'cidade_id\'] + .select2').show(); //show select2 element
},
success: function(json) {
//create the new options based on the call return
html = '<option value="#">Cidade</option>';
if (json['cidade'] && json['cidade'] != '') {
for (i = 0; i < json['cidade'].length; i++) {
html += '<option value="' + json['cidade'][i]['cityId'] + '">' + json['cidade'][i]['cityName'] + '</option>';
}
}
$('select[name=\'cidade_id\']').html(html); //replace select options on DOM
},
error: function(xhr, ajaxOptions, thrownError) {
//handle error
}
});
};
In short: by changing the select element, I hide the element that will receive the new information, make the call, add then add the information to DOM (still hidden). Finally, rerender the select2 element with the new options and then show it.
I hope this helps you.

Calling web methods through jquery AJAX and nesting AJAX

I have a problem in updating sql database table with jQuery ajax.
here is my scenario. I am working on privileges table to assign a teacher some kind of privilege/rights to perform some required functionality of the website.
1) I call a webmethod and pass teacher's id to retrive all privileges assigned to that particular teacher using jQuery ajax
2) in the success function of step 1 I call another web method using jQuery ajax and bind a click event on checkbox (on/of toggle button -- its input type was checkbox) present against every privilege listed.
3) when I click on that on/off toggle checkbox I want to update a row in sql database table in privileges table if it is on and user turns it off then that particular privilege will be unassigned to that teacher.
here is my code
public void UpdatePrivileges(string _columnName, byte _value, int _teacherid)
{
JavaScriptSerializer objserializer = new JavaScriptSerializer();
myDatabase.CreateConnection();
myDatabase.InitializeSQLCommandObject(myDatabase.GetCurrentConnection, "update tbl_privileges set " + _columnName + " = #val where teacher_id = #tid");
myDatabase.obj_sqlcommand.Parameters.AddWithValue("#tid", _teacherid);
myDatabase.obj_sqlcommand.Parameters.AddWithValue("#val", Convert.ToByte(_value));
try
{
myDatabase.OpenConnection();
myDatabase.obj_sqlcommand.ExecuteNonQuery();
}
finally
{
myDatabase.CloseConnection();
myDatabase.obj_sqlcommand.Dispose();
}
HttpContext.Current.Response.Write(objserializer.Serialize("Updated"));
}
This code is for retrieving teacher's privileges and show them on webForm.
function GetTeacherPrivileges() {
var teacherid = $('#<%=txtTeacherIDToPopulatePrivileges.ClientID%>').val();
$.ajax({
url: 'source/WebServices/GetAllTeachers.asmx/GetPrivileges',
method: 'post',
data: { _teacherID: teacherid},
datatype: 'json',
success: function (data) {
var obj = JSON.stringify(data);
var arrayjson = $.parseJSON(obj);
var actualarray = $.parseJSON(arrayjson);
$.each(actualarray, function (i, v) {
$('#tablebody').append('<tr class="table-row"> <td class="col-3"><span>Events</span></td><td class="col-2">is this teacher eligible to making events?</td><td class="col-3"><label class="switch centerbuttion "><input id="check_event" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="No"></span><span class="switch-handle"></span></label></td></tr><tr class="table-row"> <td class="col-3"><span>Attendance</span></td><td class="col-2">Do you want this teacher can mark attendance?</td><td class="col-3"><label class="switch centerbuttion "><input id="check_attendance" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="NO"></span><span class="switch-handle"></span></label></td></tr><tr class="table-row"><td class="col-3"><span>Homework</span></td><td class="col-2">Teacher will be able to upload homework with their respective classes.</td><td class="col-3"><label class="switch centerbuttion "><input id="check_homework" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="NO"></span><span class="switch-handle"></span></label></td></tr><tr class="table-row"><td class="col-3"><span>Reports</span></td><td class="col-2">Do you want this teacher to generate reports?</td><td class="col-3"><label class="switch centerbuttion "><input id="check_reports" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="NO"></span><span class="switch-handle"></span></label></td></tr><tr class="table-row"><td class="col-3"><span>Timetable</span></td><td class="col-2">Can this teacher make time table(s)?</td><td class="col-3"><label class="switch centerbuttion "><input id="check_timetable" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="NO"></span><span class="switch-handle"></span></label></td></tr><tr class="table-row"><td class="col-3"><span>Datesheet</span></td><td class="col-2">Can this teacher make Date Sheet(s)?</td><td class="col-3"><label class="switch centerbuttion "><input id="check_datesheets" class="switch-input" type="checkbox" /><span class="switch-label" data-on="Yes" data-off="NO"></span><span class="switch-handle"></span></label></td></tr>');
var event = v.Event;
var attendance = v.Attendance;
var homework = v.Homework;
var reports = v.Reports;
var timetable = v.TimeTable;
var datesheet = v.DateSheet;
if (event == 1) {
$('#check_event').trigger('click');
}
if (attendance == 1) {
$('#check_attendence').trigger('click');
}
if (homework == 1) {
$('#check_homework').trigger('click');
}
if (reports == 1) {
$('#check_reports').trigger('click');
}
if (timetable == 1) {
$('#check_timetable').trigger('click');
}
if (datesheet == 1) {
$('#check_datesheets').trigger('click');
}
$('#check_event').bind({
click: function () {
var privilegevalue = columnvalue('#check_event');
UpdatePrivilege('event', privilegevalue);
}
});
});
},
error: function (error) {
alert("Error: " + error);
}
});
This is the second AJAX code which I call in the success function of above AJAX for binding the click event.
function UpdatePrivilege(column,value) {
var teacherid = $('#<%=txtTeacherIDToPopulatePrivileges.ClientID%>').val();
$.ajax({
url: 'source/WebServices/GetAllTeachers.asmx/UpdatePrivileges',
data: { _columnName: "'"+column+"'" , _value: value , _teacherid:teacherid },
dataType: 'json',
dataContent: 'application/json; charset=utf-8',
success: function (data) {
alert('privilege updated'+data);
},
error: function(data) {
alert('Error in updating privilege' + data);
}
});
}
When I run my aspx page and input teacher's id to GetAllTeachers() function all works good and it binds the click event on checkbox against event privilege but when I click on that it gives me error from AJAX function of UpdatePrivilege() function.
If you are wanting to send json you need to stringify the data yourself. Also you don't need the extra quotes wrapping "'"+column+"'"
Try:
function UpdatePrivilege(column,value) {
// I assume you are running this within Razor context and not in a javascript file
var teacherid = $('#<%=txtTeacherIDToPopulatePrivileges.ClientID%>').val();
// create data object
var dataObj={ _columnName: column , _value: value , _teacherid:teacherid };
// stringify it
var postData = JSON.stringify(dataObj);
$.ajax({
url: 'source/WebServices/GetAllTeachers.asmx/UpdatePrivileges',
data: postData ,// stringified data
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (data) {
console.log('privilege updated', data);
},
error: function(data) {
console.log('Error in updating privilege' , data);
}
});
}

Partial View ignoring data set and not displaying

I am developing an application in ASP.NET MVC. I am working on a page that takes some user entered values and then gets a data set from them using a stored procedure. My preference is that the data is entered on the same page as it is displayed, so I am using AJAX and partial views to accomplish this. My code worked perfectly with a dummy set of simple data (simple string) but now that I am using a more advanced data set (Ienumerable) it no longer displays the partial view.
Here is part of my view (textboxes where data is entered are hidden for length purposes):
<!--SEARCH RESULTS PARTIAL FILLED BELOW-->
<div id="search-results">
</div>
<!---->
<script>
function getSearchResults() {
var SqlViewModel = {
//assign textboxes to values to pass to controller (hidden)
}
$.ajax({
type: "POST",
data: JSON.stringify(SqlViewModel),
dataType: "json",
contentType: "application/json",
url: "/Sql/Search/",
success: function(result) {
$('#search-results').html(result);
}
}); }
</script>
I grab the data from the textboxes, and then pass those values to my "Search" controller method using my ajax. (values are all passed correctly using SqlVieWModel)
Controller method:
[HttpPost]
public ActionResult Search(SqlViewModel sT)
{
//code for stored procedure
var sql = //get stored procedure and parameters
SqlPartialViewModel obj = new SqlPartialViewModel();
obj.SqlData = sql; //obj.SqlData is of type IEnumerable<Get_Result>
return PartialView("_SearchResultsPartial", obj);
SqlPartialViewModel definition:
public class SqlPartialViewModel
{
public IEnumerable<Get_Result> SqlData { get; set; }
}
Finally, I attempt to simply get this data to display in my partial view (_SearchResultssPartial.cshtml):
#model SqlPartialViewModel
<table>
<tr>
<th>//Display stuff</th>
</tr>
#foreach(var result in Model.SqlData)
{
<tr>
<td>//Display stuff</td>
</tr>
}
Nothing displays, and I receive no errors.
In you Ajax call, you're expecting a json result from the server:
$.ajax({
type: "POST",
data: JSON.stringify(SqlViewModel),
dataType: "json", <---- HERE
contentType: "application/json",
url: "/Sql/Search/",
success: function(result) {
$('#search-results').html(result);
}
});
But when you return a PartialView from an ActionResult, you're returning html type, not jsontype.
Just change the dataType to "html" or remove that line (so javascript will try to interpret by itself).

Post <Li> Items with Json and Jquery to Web Method

I am trying to pass a <li> list to a web method using json and Jquery. My goal is to return this list to C# using a Session Variable.My problem is that the session return always null. So the list never passes on Web Method.
The List:
<div>
<ol id="mycart">
<li>iPhone</li>
<li>iPod</li>
<li>iPad</li>
</ol>
</div>
<input type="button" id = "btngetCart" value="Get cart" />
The Json Script:
<script type="text/javascript">
$("#btngetCart").live("click", function () {
var items = $('.mycart').find('li').map(function() {
var item = { };
item.title = $(this).text();
return item;
});
var json = JSON.stringify(items);
$.ajax({
type: 'POST',
url: "WebForm4.aspx/GetCart",
data: "{json}",
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (r) {
}
});
});
</script>
The Web Method:
public class mycart
{
private string[] title;
}
[WebMethod(EnableSession = true)]
public static mycart GetCart(mycart title)
{
HttpContext.Current.Session["j"] = title;
return title;
}
Error here :
html : <ol id="mycart"> has id attribute
var items = $('.mycart') //used class, which does not exists, try this:
var items = $('#mycart')
AND change
data: "{json}",
to
data: json,

Categories

Resources