Javascript send an input as array to a C# WebAPI - javascript

-------------------------EDIT--------------------------------
It's not a duplicate because I can't use an ajax Request, as asked on this question.
I'm creating a form in javascript to call a c# WebApi that will return a xls file (that's why I'm creating a form and not an ajax call).
The webApi must receive an array of integer, that will correspond to a list of ids of objects.
The webApi is the following
[Route("getExcel")]
[HttpPost]
public HttpResponseMessage getExcel([FromBody]int[] ids)
{
...
}
the form I'm building is like this:
var form = document.createElement("form");
form.setAttribute('method', "post");
setAttribute('action', baseUrl + "api/processos/getExcel");
form.setAttribute('target', "_blank");
var rows = $("#tbl").dataTable().fnGetNodes();
var arr = [];
for (var i = 0; i < rows.length; i++)
{
ids = $("#tbl").dataTable().fnGetData(i).processosId;
var input = document.createElement("input");
input.setAttribute('type', "text");
input.setAttribute('name', "ids[]");
input.setAttribute('value', ids);
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
The ids on the WebApi is empty (but not null)... When watching on Fiddler, the Raw View shows this ids=15&ids=14&ids=13&ids=12&ids=11 which is exactly what I need...
Why isn't associating with the WebApi ids ? If I send that exact values in the URL (and changing the [FromBody] to [FromUri] it works...
-------------------EDIT------------------------------
this is what is in the array ids on the WebApi when the method is called:
ids {int[0]} (as seen while debugging)

So, the solution is to create a model on the backend such this:
public class ExcelIds
{
public int[] ids { get; set; }
}
and change the controller to:
[Route("getExcel")]
[HttpPost]
public HttpResponseMessage getExcel([FromBody]ExcelIds model)
{
//code here
}

You could use FormDataCollection.GetValues(string Key) to get an array of strings, that you could later convert to int[].
[Route("getExcel")]
[HttpPost]
public HttpResponseMessage getExcel(FormDataCollection data)
{
string[] ids = data.GetValues("ids");
...
}

Related

Pass js complex array to mvc controller, and then return another view

This is related to my previous question.
I'm wondering, can I pass a JS array the same way (as the accepted answer in previous question) even if now I'm trying to send a bit more complex array:
If yes, then how? Getting nulls while receiving in controller.
this is my model:
public class QuestionModel
{
public bool Choice { get; set; }
public List<object> ChoiceQuestions { get; set; } //can i use List<object>?
public int Id { get; set; }
public string Question { get; set; }
public bool Short { get; set; }
public object ShortQuestion { get; set; } //here aswell - can I use object?
public string Type { get; set; }
}
Not even sure if I can reuse the js code for sending the data to controller that was given in the answer. If no, then how should I solve this? Still I have to be able to send the data via post to controller, and then after processing data return it back to the view.
You may make Json of any object as a single hidden form field and then post the form to action with string parameter. Then on server side desterilize json to the object inside the action method - even in another controller. You may return different view from the controller method.
Javascript (Say on Stock Page/View)
var form = document.createElement("form");
var input = document.createElement("input");
input.setAttribute("type", "hidden") ;
input.setAttribute("name", "outwardStocks") ;
input.setAttribute("value", JSON.stringify(selectedrecords));
form.appendChild(input);
document.body.appendChild(form);
form.action = "/CRM/Invoice/Index";
form.method = "post"
form.submit();
Controller code (Say Invoice Controller)
[HttpPost]
public IActionResult Index(string outwardStocks)
{
InvoiceItems invItems = JsonSerializer.Deserialize<InvoiceItems>(outwardStocks);
......
return View("Invoice" InvoiceVM);
}

Get correct checkbox value when using razor asp.net mvc

I am rendering my form using razor. I iterate over class .control_group that's inside a form and create objects that I need to send back to controller. My form has checkboxes and hidden input values. Problem I am facing now is this. Checkbox elements rendered by razor have two inputs, one is hidden and other one is shown. When I collect form data I am always getting last input value (hidden one, and it's always false) How can I get the true value?
Current data sent to controller (everything is false):
{"ajaxData":[{"Id":"1","RoleId":"1","R":"false","W":"false","E":"false","D":"false"},{"Id":"2","RoleId":"2","R":"false","W":"false","E":"false","D":"false"}]}
Collecting data like this (found similar problem here on SO):
var ajaxData = $('.control_group').map(function (i, group) {
var data = {};
$(group).find(':input').each(function () {
data[this.name] = this.value;
});
return data;
}).get();
ajaxData = JSON.stringify({ 'ajaxData': ajaxData });
console.log(ajaxData);
Controller looks like this:
public void SendData(List<SomeClass> ajaxData)
{
var data = ajaxData;
}
public class SomeClass
{
public int Id { get; set; }
public int RoleId { get; set; }
public bool R { get; set; }
public bool W { get; set; }
public bool E { get; set; }
public bool D { get; set; }
}
It is by design, you can read about this here: asp.net mvc: why is Html.CheckBox generating an additional hidden input
I can suggest you while iterating the elements do the following
if the form has another element with the same name, and it is not check box, skip it.
this way you can just collect the correct fields.
I am most certainly sure that you can handle this with JQUERY, if not, post a JSFIDDLE so we can help you.
Razor syntax always creates a hidden field for radio button & checkbox. You can change your :input selector to :input:checkbox to do your task.
var ajaxData = $('.control_group').map(function (i, group) {
var data = {};
$(group).find(':input:checkbox').each(function () {
data[this.name] = this.value;
});
return data;
}).get();
ajaxData = JSON.stringify({ 'ajaxData': ajaxData });
console.log(ajaxData);

ASP.NET MVC - How to "reverse" model binding to convert a C# model back to a query string representation

I have a custom javascript on the client side that I use to build up a querystring and pass over to my asp.net-mvc controller
var templateQueryString = BuildTemplate();
$.ajax({
url: '/MyController/Save?' + templateQueryString,
type: 'post',
dataType: 'json',
success: function (data) {
}
}
and on my controller all of the properties leverage the model binding so it comes in as a single object on the server side. NOTE: that this is a pretty complex object with arrays and arrays of sub objects:
public ActionResult Save(MyTemplate template)
{
}
the issue now is that I need to be able to convert from my C# object back to a string that represents "myTemplateQueryString" on the client side.
Is there any recommended way to take an object and do the "reverse" model binding. They key here is that it generates a string that I could use as a query string again in the future to pass into another asp.ent-mvc controller action.
Here is an example of the querystring that I am storing locally:
<input type="hidden" value="showIds=false&showRisks=false&
amp;statusIds=2&statusIds=1&statusIds=6&statusIds=8&
amp;statusIds=3&statusIds=9&showCompleted=0"
name="filterQueryString" id="filterQueryString">
As #haim770 said it would be easier if you used JSON in the request payload, and not the query string to pass your complex object to the server.
Regarding creating the query string from a model there is not a built-in method that does something like that or any recommended approach as far as i know. An obvious solution is to use reflection and build the query string from your properties.
Assuming your BuildTemplate class looks something like:
public class BuildTemplate
{
public bool ShowIds { get; set; }
public bool ShowRisks { get; set; }
public bool ShowCompleted { get; set; }
public int[] StatusIds { get; set; }
}
You can develop an extension method to convert any object to a QueryString. Here is some initial code you can start with:
public static class ObjectExtensions
{
public static string ToQueryString(this Object obj)
{
var keyPairs = obj.GetType().GetProperties().Select(p =>
new KeyValuePair<string, object>(p.Name.ToLower(), p.GetValue(obj, null)));
var arr = new List<string>();
foreach (var item in keyPairs)
{
if (item.Value is IEnumerable && !(item.Value is String))
{
foreach (var arrayItem in (item.Value as IEnumerable))
{
arr.Add(String.Format("{0}={1}", item.Key, arrayItem.ToString().ToLower()));
}
}
else
arr.Add(String.Format("{0}={1}", item.Key, item.Value.ToString().ToLower()));
}
return "?" + String.Join("&", arr);
}
}
Then you can easily invoke this code on any object to generate a query string:
var person = new BuildTemplate() { StatusIds = new []{ 1, 5, 8, 9 }, ShowRisks = true };
var queryString = person.ToQueryString();
This would generate a query string like:
"?showids=false&showrisks=true&showcompleted=false&statusids=1&statusids=5&statusids=8&statusids=9"
This query string should work just fine with the default model binder for the BuildTemplate class.

Controller Action parameter not properly populated from AJAX POST

I'm performing an AJAX call and I want the Controller Action (using HttpPost) to accept a parameter of IEnumerable<PercentageViewModel> percentages
where PercentageViewModel is:
public class PercentageViewModel
{
public int Id { get; set; }
public string Percentage { get; set; }
}
The populated data structure on the Action has 2 items in the collection but each item is filled with default values (0 and null). Here is the data as it appears in Chrome Network Headers - when I click on the AJAX Post XHR call
percentages[0][Id]:7
percentages[0][Percentage]:26.1
percentages[1][Id]:8
percentages[1][Percentage]:20.3
Here is the JS where I am populating the params variable that will be sent using the AJAX Post call.
var params = {};
var dict = [];
for (var idx in data) {
var item = {
Id: idx,
Percentage: data[idx]
};
dict.push(item);
}
params['percentages'] = dict;
where the data variable has data like this (when written to Chrome console):
Object {7: "26.1", 8: "20.3"}
How can I construct the data in JS so the data structure in the Action is populated properly?
Full disclosure: this is a rephrasing of a question I asked yesterday - just as a more targeted question.
This was the answer that allow the server side data structure to be populated properly
var i = 0;
for (var idx in data) {
params['percentages[' + i + '].Id'] = data[idx].Id;
params['percentages[' + i + '].Percentage'] = data[idx].Percentage;
i++;
}

Present JSON data to a play framework template

Trying to get it to work without any detail knowledge of JQuery. I am really having a hard time finding an comprehensible example of how i would create an unnumbered list out of some json that i am passing to the front inside a String object.
I am using the Play! Framework. My Application has a method that returns a string holding an json array of items.
GET /items controllers.Application.items()
the method looks like this:
public static Result items() {
return ok(Json.toJson(Item.all()));
}
How would you process this data in order to have your template present it as an unnumbered list?
the data, example:
#Entity
public class Item {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int id;
public String title;
public String type;
public int quantity;
public BigDecimal unitPrice;
public Item() {}
public static List<Item> all() {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("defaultPersistenceUnit");
EntityManager entityManager = entityManagerFactory.createEntityManager();
TypedQuery<Item> query = entityManager.createQuery("SELECT i FROM Item i", Item.class);
return query.getResultList();
}
You need to call the items() action with a javascript ajax request. Then you can use javascript and jQuery to create your list.
something like this:
<script type="text/javascript">
$(function(){
$.getJSON('/items', function(items){
var ul = $('<ul>');
$.each(items, function(item){
var li = $('<li>').text(item.title);
ul.append(li);
});
$('body').append(ul);
});
});
</script>

Categories

Resources