getting JSON string into Knockout observable multiselectlist - c#

I am trying to get my JSON string passed through the ViewBag into my knockout observable and use that to populate a multiselectlist. I'm not sure what I am doing wrong, but right now it is taking each individual character in the JSON string and sticking it in it's own line in the select list.
Here is my C# controller code:
Dictionary<string, string> salesReps = new Dictionary<string, string>();
foreach ( var rep in salespeople.Salesperson )
{
salesReps.Add( rep.Code, rep.Code + " - " + rep.fullName );
}
//ViewBag.salespeople = salespeople.Salesperson.Select( x => x.Code ).Distinct().ToList();
ViewBag.salespeople = JsonConvert.SerializeObject( salesReps );
And here is the Knockout code:
var cSource = function (data) {
var self = this;
.....
self.salesPeople = ko.observableArray();
};
$(document).ready(function () {
var modelData = #Html.Raw( Json.Encode( Model ) );
mySource = new cSource(modelData);
//var salesRepList = Html.Raw( Json.Encode( ViewBag.salespeople ) );
var salesRepList = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.salespeople));
console.log(salesRepList);
mySource.salesPeople = salesRepList;
And here is the HTML select code:
<select data-bind="
options: salesPeople,
selectedOptions: chosenReps,
optionsCaption: 'Choose rep(s)'
"></select>
And a small snippet of what my console.log spits out:
{"USERNAME1":"USERNAME1 - Full Name 1","USERNAME2":"USERNAME2 - Full Name 2","USERNAME3":"USERNAME3 - Full Name 3",..... }
UPDATE
I changed the c# code to create named variables in the JSON now. Here is my new console.log output:
{"username":"BOBC","fullname":"Bob Cottin"},{"username":"JIMT","fullname":"Jim Thorpe"},{"username":"LUKEP","fullname":"Luke Peppin"}, ....}

The options binding is expecting an array of objects or values, but according to your console log salesPeople is a single dictionary style object. You may need to convert that to an array so the binding knows how to parse it into select options.
If you only need the value property and can disregard the "Username1", "Username2", etc then you could use a loop like this to grab the value properties of the object:
for (var x in salesRepList) {
if (salesRepList.hasOwnProperty(x)) {
mySource.salesPeople.push(salesRepList[x]);
}
}
If you need the more complex types then you'll have to create an array of objects, or (per your last edit) have your json pass them with standard parameter names. Then you can use knockout's optionsText binding to tell the select which property on the object to use as the display text.
Per example:3 of the knockout docs
<select data-bind="options: availableCountries,
optionsText: 'countryName',
value: selectedCountry,
optionsCaption: 'Choose...'"></select>
Here's a jsFiddle with some of that adapted to your example: fiddle

Related

How to get value from a List of Items from View by using jquery

I have a list View as:
#foreach(var item in model )
and it has some field as:
#html.DisplayFor(modelItem =>item.prodname ,new{#class="pn"})
I wanted to select a value of this prodname in jquery.
For this I have tried the following process but it doesn't give the required output.
$("#convt").click(function () {
$.each(item, function () {
var snm = (this,'.pn').val().trim();
});
alert(snm);
});
What correction do I need to select a value of this prodname in jquery?
$(".class-name").text() should work, to get the text of element using class name.

How to use IEnumerable<ExpandoObject> in knockout.js?

Problem Description
I wanted to ask about how to use a list Exbando Objects in knockout.js,am using Rob Conrey's Massive and all returned results are dynamic, that's fine with me it suits my needs but when it comes to sending results to knockout i just don't know what to do with it.
Goal
Access object properties like obj.Name, obj.Brand etc...
Sample Code
View:
<div data-bind="foreach: Products">
<p>Product name: <strong data-bind="text: Name"></strong></p>
</div>
Controller:
public JsonResult GetProducts()
{
Products products = new Products();
var Model = products.GetAllProducts();
return Json(Model, JsonRequestBehavior.AllowGet);
}
The result of calling GetProducts is:
[[{"Key":"Id","Value":1},{"Key":"Name","Value":"Badass Boots"},{"Key":"Brand","Value":"Nike"},{"Key":"Description","Value":"Super cool boots that can make you fly (Not Really!)."}, etc...]]
Script File:
function ProductListViewModel() {
// Data
var self = this;
self.Products = ko.observableArray([]);
$.getJSON("/Home/GetProducts", function (data) {
self.Products(data);
});
}
JavaScript error on running the application:
Uncaught ReferenceError: Unable to parse bindings. Bindings value: text: Name Message: Name is not defined
Screen Shot 1:
Screen Shot 2:
An ExpandoObject generally speaking is for all intents and purposes, a dictionary. When serialized as JSON here, it is treated as a dictionary and becomes a collection of key/value pairs (not all serializers behave this way, but the one you're using does). It is not an object you can access members by name, you'll have to convert it into a representation where you can (or serialize it as one in the first place).
Doing the conversion is not the worst thing in the world:
function Product(item) {
var self = this;
// assuming item is an array of key/value pairs
ko.utils.arrayForEach(item, function(pair) {
// doesn't necessarily have to be mapped as an observable
self[pair.Key] = ko.observable(pair.Value);
});
}
With this, you can then map the results to your array of products:
$.getJSON("/Home/GetProducts", function (data) {
self.Products(ko.utils.arrayMap(data, function(item) {
return new Product(item);
}));
});
It looks like the problem is because you are trying to set the value of your ko.observableArray to a json array. Not sure that this will work. Typically this is how I would do it:
function ProductListViewModel() {
// Data
var self = this;
self.Products = ko.observableArray([]);
$.getJSON("/Home/GetProducts", function (data) {
ko.utils.arrayForEach(data, function(item) {
self.Products.push({
Name : item.Name
});
});
});
}
Use knockout's arrayForEach function to iterate through your json array, and push each object into your observableArray.
As in your JSON I see the sequence of Key and Value, so you have to specify the filed name which knockout has to query for to get the relative value and put it on the screen.
So change <strong data-bind="text: Name"> to <strong data-bind="text: Key"> and this should work for you.

Serialize HTML Form in JavaScript and then Convert to a .NET Type in C#

I'm trying to take a HTML form and serialize the fields so that it can be stored as attributes against an element in JavaScript (you can use jQuery). This can later be parsed in C# and converted to a .NET type. This must work for any type as the form is generated via an Ajax call to the server.
For example given the following form:
<form>
<input type="text" name="Assembly" value="MyAssembly.dll" />
<input type="text" name="Class" value="MyClass" />
<input type="text" name="Parameters.Parameter1" value="5" />
<input type="text" name="Parameters.Parameter2" value="10" />
</form>
It would produce something like:
<widget assembly="MyAssembly.dll" class="MyClass" parameters="???"></widget>
Note: ??? would be replaced with either JSON or XML (depending on your which you think is best).
Now say I stored this string in the database I need to parse it on the server to convert it to a .NET type. I can do a regular expression to get the appropriate attributes leaving me with the following variables:
var assembly = "MyAssembly.dll";
var #class = "MyClass";
var parameters = "???";
Now finally I need to serialize this to a .NET type.
I'd appreciate it if someone could help. Thanks
I've come up with something that works. My solution is slightly more complicated but I'll try to post the key bits in case anyone is interested.
First I created the following plugins:
$.fn.serializeObject = function(prefix) {
var o = {};
// Serialize the form as an array
var a = this.serializeArray()
.filter($.proxy(function(element) {
// Make sure the prefix matches and it is not a checkbox (this is needed since ASP.NET MVC renders a hidden checkbox for the false value)
return element.name.indexOf(prefix || '') == 0 && $('[name=\'' + element.name + '\'][type=\'checkbox\']', this).length == 0;
}, this));
// Now append the checkbox values (this makes sure we only have one element in the array with the correct value whether it is selected or not)
a = a.concat($('input[type=\'checkbox\']', this).map(function() {
return { 'name': this.name, 'value': $(this).is(':checked') ? 'true' : 'false' }
}).get());
$.each(a, function() {
var n = this.name.substr((prefix || '').length);
if (o[n] !== undefined) {
if (!o[n].push)
o[n] = [o[n]];
o[n].push(this.value || '');
} else
o[n] = this.value || '';
});
return o;
};
Now for my application I actually have a WYSIWYG plugin which embeds my custom widget tag within the editor. Here's an example of what you could do to create the widget tag from the form when it is submitted (this would then be stored in the database):
$('form').submit(function(e) {
var parameters = JSON.stringify($('form').serializeObject('Parameters.'));
var widget = '<widget assembly="' + $('[name=\'Assembly\']').val() + '" class="' + $('[name=\'Class\']').val() + '" parameters="' + parameters + '"></widget>';
...
});
Finally on the server you need to replace the widget on display by doing something like:
output = Regex.Replace(output, #"<widget assembly=""(.*?)"" class=""(.*?)"" parameters=""(.*?)""></widget>", m => ReplaceWidget(m, helper));
Here's the ReplaceWidget method:
private static string ReplaceWidget(Match match, HtmlHelper helper) {
var assembly = match.Groups[1].Value;
var #class = match.Groups[2].Value;
var serializedParameters = match.Groups[3].Value;
// Get the type
var type = Assembly.LoadFrom(HttpContext.Current.Server.MapPath("~/bin/" + assembly)).GetType(#class);
// Deserialize the parameters
var parameters = JsonConvert.DeserializeObject(HttpUtility.HtmlDecode(serializedParameters), type);
// Return the widget
return helper.Action("Widget", "Widgets", new { parameters = parameters }).ToString();
}
Hope this helps.

Get HTML Dropdownlist selected item in Razor Webpages

I am having some difficulty figuring out how to return the selected item in my HTML.DropDownList so that upon hitting a submit button, the selected item text will be looked up in my database. Here is what I have:
#{
var selectStaff = "Select LastName + ', ' + FirstName AS Name, StaffID From StaffList ORDER BY LastName";
var data = db.Query(selectStaff);
var items = data.Select(i => new SelectListItem {
Text = i.Name
});
}
And then in the html..
#Html.DropDownList("Select1", items)
This works fine, as my dropdownlist is appearing and is populated, but now upon hitting a submit button, I want to be able to search that text of the selected item in my database. How would I go about doing this?
If you don't bind the dropdown to a property on your view model (which would be preferable), you can still get it simply using Request.Form["Select1"] in your controller action.
If you mean that you want to be able to get the value while still on the razor page, you need to use jQuery (or other javascript) to get the value.
To get the value with jQuery:
$(document).ready(function () {
$("#YourSubmitButtonID").click(function () {
// Get the value from 'Select1'
var value = $("#Select1").val();
});
});
To do something with the value, you would have to use an ajax function, something like this:
$.ajax({
url: '#Url.Action("ActionName", "ControllerName")',
data: { valueToQuery: $("#Select1").val() },
success: function (data) {
// The data is the result
}
});
On the controller named ControllerName in this example, you'd have the code that queries the database and returns your result.
public ActionResult ActionName(string valueToQuery)
{
// Do your stuff here
return Json("your result", , JsonRequestBehavior.AllowGet);
{
I have also found THIS very interesting that May help you out!
You may also try the following Steps if you don't want to use Ajax or Json tactics:
var sql = "SELECT ProductId, ProductName FROM Products";
var data = Database.Open("Northwind").Query(sql);
var items = data.Select(i => new SelectListItem {
Value = i.ProductId.ToString(),
Text = i.ProductName
});
#Html.DropDownList("productid", items)
And Also:
var sql = "SELECT ProductId, ProductName FROM Products";
var data = Database.Open("Northwind").Query(sql);
<select name="productid">
#foreach(var row in data){
<option value="#row.ProductId">#row.ProductName</option>
}
</select>

How to send an object to the Telerik MVC Grid Ajax Select() Controller Method

I am using the Telerik MVC Grid with Ajax binding, and am having a problem passing an object to the controller to be used to filter data. I am able to pass simple data (string, int), but not a more complex object.
For instance, I can to this no problem:
.DataBinding(dataBinding => dataBinding.Ajax().Select("_CasesAjaxBinding", "Home", new {orderId = "12345"} ))
And then in my controller, handle the orderId like this:
public ActionResult _CasesAjaxBinding(string orderId)
The problem I am having is when I try to pass a more complex object (in this case the #Model) to the controller, like this (The #Model is type CaseFilterModel):
.DataBinding(dataBinding => dataBinding.Ajax().Select("_CasesAjaxBinding", "Home", new {filterSpec = #Model} ))
And then trying to handle the object, like this:
public ActionResult _CasesAjaxBinding(CaseFilterModel filterSpec)
The filterSpec parameter is always null.
Thanks in advance for any ideas!
As far as I can find on the Telerik forums this cannot be done this way. There was a similar question on there, which described exactly the same problem. When passing the model it was always null in the controller's action method.
However there is a workaround if you want to pass multiple parameters to the select method in order to filter the data, but it requires some client side coding.
I'll include a summary of that work around here, so that the answer is complete. A solemn link doesn't say much.
Assume we have a grid which displays orders items (articles) from all the orders. First make sure to hook up the client side onDataBinding event:
<%= Html.Telerik().Grid<Order>()
.Name("Grid")
.ClientEvents(events => events.OnDataBinding("onDataBinding"))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("_AjaxBinding", "Grid"))
%>
In the client side event handler you need to compose your select URL. Here I'll pass two parameters, an order id (int) and a description of an article (string).
<script type="text/javascript">
function onDataBinding(e) {
var orderId = 100;
var searchText = "test";
var params = { OrderId: orderId, ArticleDescription: searchText };
var paramsStr = $.param(params);
var selectUrl = "<%= #Url.Action("_AjaxFilterBinding", "Grid") %>"
+ "?" + paramsStr;
var grid = $('#Grid').data('tGrid');
grid.ajax.selectUrl = selectUrl;
}
</script>
Then in your controller you can declare the select method as follows:
[GridAction]
public ActionResult _AjaxFilterBinding(AjaxFilterBindingModel model)
{
// Retrieve data here and filter it based upon the data present in the model.
var data = ...;
return View(new GridModel<Order> { Data = data });
}
The model looks like:
public class AjaxFilterBindingModel
{
public int OrderId { get; set; }
public string ArticleDescription { get; set; }
}
Passing a collection via the URL (GET) is also possible. Let's assume you want a collection of order IDs instead of just one.
The model would look like this:
public class AjaxFilterBindingModel
{
public IEnumerable<int> OrderIds { get; set; }
public string ArticleDescription { get; set; }
}
And the JavaScript would look like this:
function onDataBinding(e) {
jQuery.ajaxSettings.traditional = true;
var intArray = [1, 2, 3, 4, 5];
var params = { OrderIds: intArray, ArticleDescription: "Test" };
var paramsStr = $.param(params);
var selectUrl = "<%= #Url.Action("_AjaxFilterBinding", "Home") %>" + "?"
+ paramsStr;
var grid = $('#Grid').data('tGrid');
grid.ajax.selectUrl = selectUrl;
}
Remark: Don't forget to set "jQuery.ajaxSettings.traditional = true;" or the parameters will be serialized incorrectly and the ASP.NET MVC model binder will not be able to bind the integer array.
And to be complete here is the Telerik forum thread I mentioned:
http://www.telerik.com/community/forums/aspnet-mvc/grid/getting-the-model-object-in-a-custom-binding-grid-ajax-controller.aspx
And the suggested work around:
http://www.telerik.com/community/forums/aspnet-mvc/grid/code-sample-sending-additional-filters-with-ajax-binding.aspx
Also as a note, this solution is not in Razor syntax... took me forever to spot it but the line
var selectUrl = "<%= #Url.Action("_AjaxFilterBinding", "Home") %>" + "?" + paramsStr;
should be changed to
var selectUrl = "#Url.Action("_AjaxFilterBinding", "Home")" + "?" + paramsStr;
For Razor... I copied the code but couldn't figure out why my _AjaxFilterBinding was not being called. Just thought I'd point it out in case anyone else has this problem.
Thanks for the solution, it NOW works great :)

Categories

Resources