Pass an array to WebAPI from AngularJS and read from WebAPI - javascript

Let's say I have an array in my client side model:
vm.dataSheets = [
{ value: 0, text: localize.getLocalizedString('_ProductsAndServices_'), selected: selected},
{ value: 1, text: localize.getLocalizedString('_Holidays_'), selected: selected },
{ value: 2, text: localize.getLocalizedString('_Locations_'), selected: selected },
{ value: 3, text: localize.getLocalizedString('_OpHours_'), selected: selected },
{ value: 4, text: localize.getLocalizedString('_Users_'), selected: selected }
];
I bind this to a checkbox list on the HTML. I want to send the values of those which are checked, to the web API. Using angularJS I can filter the selected objects as follows:
$filter('filter')(vm.dataSheets, { selected: true })
This will return an array of the entire object. Is there a short way to just retrieve the selected values as 1,2,3, etc...?
Right now, I send the data to the Web API as follows:
var fd = new FormData();
fd.append('file', file);
fd.append('clientId', $rootScope.appData.clientId);
fd.append('sheets', $filter('filter')(vm.dataSheets, { selected: true }));
$http.post("TIUSP/systemengine/ClientSupply", fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success(function () {
}
In the web API, how do I retrieve the selected values? When I use
HttpContext.Current.Request["sheets"];
it gives me a string as [object, object][object, object], etc...

To return the selected values as an array with Ids, you can create a custom filter:
app.filter('selected', function() {
return function(items) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.selected === true) {
filtered.push(item.id);
}
}
return filtered;
};
});
Then, use it:
var fd = {
'file': file,
'clientId': $rootScope.appData.clientId,
'sheets': $filter('selected')(foo.results)
};
$http.post("TIUSP/systemengine/ClientSupply", fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success(function () {
}
This will create something like this:
{
file: 'path-to-my-filez/image.png',
clientId: 11,
sheets: [1,2,3,4]
}
In your Web API Controller
Create a class that maps the parameters you are sending in your request:
public class ClientSupplyViewModel
{
public string file {get; set;}
public int clientId [get; set;}
public int[] sheets {get; set;}
}
Then, use it in your controller:
[HttpPost]
public HttpResponseMessage ClientSupply(ClientSupplyViewModel data)
{
}
The controller above is just an example. The only important part is the data parameter which contains your File, ClientId and the array of ints.

Related

How to post list data to .net mvc using Axios with out [FromBody] model binding

I am try to post object list to backend using Axios.
But backend couldn't get any object list parameters.
Code:
<div class="text-center">
<button onclick="postData()">Post Data</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.js"></script>
<script>
function postData() {
let mockData = [];
mockData.push({ ID: 0, Name: "John" });
mockData.push({ ID: 1, Name: "Mary" });
mockData.push({ ID: 2, Name: "Alex" });
mockData.push({ ID: 3, Name: "July" });
mockData.push({ ID: 4, Name: "Steve" });
console.log(mockData);
const formData = new FormData();
formData.append('model', mockData);
axios.post('/Home/Receive', formData)
.then(res => console.log(res.data))
.catch((error) => { console.error(error) });
}
</script>
[HttpPost]
public IActionResult Receive(List<MemberInfo> model)
{
var itemList = model;
return View();
}
public class MemberInfo
{
public int ID { get; set; }
public string Name { get; set; }
}
The above code, backend always get null.
Result:
Awayls get null when post to this function.
Even I add [FromQuery] or [FromForm] in function.
I know I can use [FromBody] to get object list. So how can I get object list without [FromBody] ?
Based on the code of your controller action and model class, to post data and bind value to properties of the model, you can try:
Approach 1: generate and post formdata like below on your JavaScript client side.
function postData() {
let mockData = [];
mockData.push({ ID: 0, Name: "John" });
mockData.push({ ID: 1, Name: "Mary" });
mockData.push({ ID: 2, Name: "Alex" });
mockData.push({ ID: 3, Name: "July" });
mockData.push({ ID: 4, Name: "Steve" });
console.log(mockData);
const formData = new FormData();
//formData.append('model', JSON.stringify(mockData));
for (var i = 0; i < mockData.length; i++) {
formData.append(`model[${i}].ID`, mockData[i].ID);
formData.append(`model[${i}].Name`, mockData[i].Name);
}
axios.post('/Home/Receive', formData)
.then(res => console.log(res.data))
.catch((error) => { console.error(error) });
}
Approach 2: implement and use your own custom model binder, like below.
MemberInfoModelBinder class
public class MemberInfoModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
// ...
// implement it based on your actual requirement
// code logic here
// ...
//var options = new JsonSerializerOptions
//{
// PropertyNameCaseInsensitive = true
//};
var model = JsonSerializer.Deserialize<List<MemberInfo>>(bindingContext.ValueProvider.GetValue("model").FirstOrDefault());
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Receive action
[HttpPost]
public IActionResult Receive(
[ModelBinder(BinderType = typeof(MemberInfoModelBinder))]List<MemberInfo> model)
{
var itemList = model;
return View();
}
On JavaScript client side
const formData = new FormData();
formData.append('model', JSON.stringify(mockData));
Test Result
Invoking you post action like this:
axios.post('/Home/Receive', formData)
Will always put the data in the body of the request.
If you wish to get it for example from query, you would have to adjust both the backend and the client javascript call:
[HttpGet]
public IActionResult Receive([FromQuery]List<MemberInfo> model)
{
var itemList = model;
return View();
}
... JS
axios.get('/Home/Receive', formData)
.then(res => console.log(res.data))
.catch((error) => { console.error(error) });
Update:
If you want it as a POST action, without the [FromBody] attribute, you can add a [ApiController] attribute to your controller - that's the second option you could use

$.post always getting null values into server

Ok, this might be simple, I'm having a simple $.post call to server sending string array as parameters..
$.get('/home/ReadCalPacTagValue', data, function (data) {
data = $.parseJSON(data);
if (data.length != 0) {
var ReadFromDb = data[0]["PushToDb"].replace('PushToDb','ReadFromDb');
var DBAckno = ReadFromDb.replace('ReadFromDb', 'DataAck');
var FIdTag = ReadFromDb.replace('ReadFromDb', 'FluidTypeId');
var UserIdTag = ReadFromDb.replace('ReadFromDb', 'UserId');
var UniqueIdTag = ReadFromDb.replace('ReadFromDb', 'UniqueRecordId');
var dbconnTag = ReadFromDb.replace('ReadFromDb', 'DatabaseConnectionString');
updateTags = [dbconnTag,FIdTag,ReadFromDb, UserIdTag,UniqueIdTag];
actionvalue = ["", fluidtypeid, '1', userid, uniqueID];
var data_Tags = { updateTags: updateTags, actionvalue: actionvalue }
$.post('/home/WriteCalPacTagValue', data_Tags, function (response) {
//var Path = "Config/16_CalPac/" + FluidType + "/" + metername + "/" + FileName
//$.cookie('FileName', FileName, { expires: 7, path: '/' });
//$.cookie('FilePath', Path, { expires: 7, path: '/' });
//$.cookie('ModuleName', "CalPac", { expires: 7, path: '/' });
//window.open('../home/CalPac', '_blank');
});
} else {
swal("Error !", "Data operation tag not binded for this product", "warning");
}
})
my problem is, every time it makes $.post call, server is getting null values int prarameters..
public void WriteCalPacTagValue(string[] updateTags, string[] actionValue)
{
string[] writetags = { };
DanpacUIRepository objNewTag = new DanpacUIRepository();
if (updateTags.Count() > 0)
{
actionValue[0] = ConfigurationManager.AppSettings["DBString"].ToString();
for (int i = 0; i < updateTags.Count(); i++)
{
writetags = updateTags[i].Replace("<", "").Replace(">", ">").Split('>');
objNewTag.WriteTag(writetags, actionValue[i]);
}
}
}
I'm not getting what I've done wrong here.. whereas same function is working from another JS file with some difference string into array updateTags.
any help?
Having
public class DataTags
{
public string[] UpdateTags { get; set; }
public string[] ActionValue { get; set; }
}
At the server: Change the method to this
[HttpPost()]
public void WriteCalPacTagValue([FromBody]DataTags data_Tags)
{
}
At the client: call it
$.ajax({
type: 'POST',
url: '/home/WriteCalPacTagValue',
data: data_Tags,
success: function (response) {
//your code
}
});
Also you can send the whole data as json string using data: JSON.stringify(data_Tags), in javascript code the change the WriteCalPacTagValue to accept a single string at the parameter and deserialize it in C# code at the server side.
EDIT if you cannot change the server side code, you may follow this as stated in the comments.

How display ajax data in select2.js v4.0?

I am using select2 v4.0 https://select2.github.io/ in an asp mvc project and I want display a simple dropdown from dynamic Data
The old way of version 3.6 doesn't work anymore:
I have a c# methode:
public JsonResult GetSrcMethod()
{
var list = new[]
{
new { id= 0, text= "Smith" },
new { id= 1, text= "John" },
new { id= 2, text= "Philippe" },
}.ToList();
Object json = JsonConvert.SerializeObject(list);
return Json(json, JsonRequestBehavior.AllowGet);
}
Thus, the data returned is:
[{"id":0,"text":"Smith"},{"id":1,"text":"John"},{"id":2,"text":"Philippe"}]
And I have a javascript code which worked on previous version 3.6:
$(".example-select2").select2({
ajax: {
dataType: 'json',
url: '#Url.Action("GetSrcLanguages", "GetCheckSet")',
results: function (data) {
return {results: data};
}
}
});
It render an empty dropdownlist that displays 'No result found'
Do you know how to do it in v4.0?
Id is not the same as id, properties on JavaScript objects are case-sensitive. The same applies to Text and text as well, you want to use the all-lowercase versions.
public JsonResult GetSrcLanguages()
{
var list = new[]
{
new { id = 0, text = "Smith" },
new { id = 1, text = "John" },
new { id = 2, text = "Philippe" },
}.ToList();
Object json = JsonConvert.SerializeObject(list);
return Json(json, JsonRequestBehavior.AllowGet);
}
Also, the ajax.results method was renamed to ajax.processResults in 4.0.0 to avoid conflicting with AJAX transports that have an existing results method. So your JavaScript should actually look like
$(".example-select2").select2({
ajax: {
dataType: 'json',
url: '#Url.Action("GetSrcLanguages", "GetCheckSet")',
processResults: function (data) {
return {results: data};
}
}
});

Web API string parameters and POST values

I am using a jQuery plugin, jTable. The plugin has the following function to load the table:
$('#PersonTable').jtable('load', { CityId: 2, Name: 'Halil' });
The values in the load function is send as POST data. The plugin also sends two query string parameters (jtStartIndex, jtPageSize) through the URL for paging the table.
An example in the documentation shows a function on how to handle this in ASP.NET MVC but not in Web API Example :
[HttpPost]
public JsonResult StudentListByFiter(string name = "", int cityId = 0, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = null)
{
try
{
//Get data from database
var studentCount = _repository.StudentRepository.GetStudentCountByFilter(name, cityId);
var students = _repository.StudentRepository.GetStudentsByFilter(name, cityId, jtStartIndex, jtPageSize, jtSorting);
//Return result to jTable
return Json(new { Result = "OK", Records = students, TotalRecordCount = studentCount });
}
catch (Exception ex)
{
return Json(new { Result = "ERROR", Message = ex.Message });
}
}
How my function currently looks: It works fine except that I can't manage to read the POST data (name param):
public dynamic ProductsList(string name = "", int jtStartIndex = 0, int jtPageSize = 0 )
{
try
{
int count = db.Products.Count();
var products = from a in db.Products where a.ProductName.Contains(name) select a;
List<Product> prods = products.OrderBy(x => x.ProductID).ToList();
return (new { Result = "OK", Records = prods, TotalRecordCount = count });
}
catch (Exception ex)
{
return (new { Result = "ERROR", Message = ex.Message });
}
}
My jTable load: (This get called when the user enters text in a input)
$('#ProductTable').jtable('load', {
name: $('#prodFilter').val()
});
I would appreciate any help with how to read both the string parameters in the URL and the POST data in a Web API function.
EDIT:
I used an alternative way to send the data to the API. Instead of sending it in the load function formatted as JSON I used a function for the listAction and sent the data through the URL (See jTable API reference for details):
listAction: function (postData, jtParams) {
return $.Deferred(function ($dfd) {
$.ajax({
url: 'http://localhost:53756/api/Product/ProductsList?jtStartIndex=' + jtParams.jtStartIndex + '&jtPageSize=' + jtParams.jtPageSize + '&name=' + $('#prodFilter').val(),
type: 'POST',
dataType: 'json',
data: postData,
success: function (data) {
$dfd.resolve(data);
},
error: function () {
$dfd.reject();
}
});
});
}
To reload the table based on your filtered results:
$('#ProductTable').jtable('load');
Instead of this:
$('#ProductTable').jtable('load', {
name: $('#prodFilter').val()
});
Try applying the [FromBody] attribute to the name parameter
public dynamic GetProductList([FromBody]string name = "", int jtStartIndex = 0, jtPageSize = 0)
{
...
}
The default binder in Web API will look in the URI for simple types like string, specifying the FromBody attribute will force it to look in the body.

How do I generate a treeView based on remote data using Kendo UI TreeView?

I have been reading ALL of the documentation on this and I still cannot get it to work.
I have a Web API which provides a JSON object. It's a list of 22 things. Just 22 lines of text.
I want to take these and form a TreeView. Each of these 22 strings will have items under them but I just want to get the first part working.
My first question is, how do I extract data from an API and populate a treeView with it?
On my main page, I have this:
<div id="treeView"></div>
On my JavaScript file I have this:
$("#treeView").kendoTreeView({
checkboxes: true,
dataSource: {
transport: {
read: {
url: "http://...",
dataType: "json"
}
}
}
});
When I try to run the page, I get "Request failed." [Retry]
If I open up a browser and go to this URL, data is returned fine as a JSON object.
What am I doing wrong here?
EDIT -
Code that is returning the JSON:
public List<string> getNotificationByUser(int id)
{
List<string> notificationTitles = new List<string>();
foreach (var notification in notifications)
{
notificationTitles.Add(notification.ToString());
}
return notificationTitles;
}
Ok! I've been able to reproduce your error. The question is that 22 lines of text are not a valid JSON.
Returning something like:
This
is
a
test
Is not a valid JSON.
But a valid JSON is not enough, you should return something like this:
[
{ "text": "This" },
{ "text": "is" },
{ "text": "a" },
{ "text": "test" }
]
I.e.: The result should be an array of objects where each object has a text field.
NOTE I know that it does not have to be called text but for simplicity I used it since it is the default value.
I figured out all of my answers:
function CreateNotificationTree(userId)
{
debugger;
var data = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "../api/notifications/byuserid/" + userId,
contentType: "application/json"
}
},
schema: {
model: {
children: "notifications"
}
}
});
$("#treeview").kendoTreeView({
dataSource: data,
loadOnDemand: true,
dataUrlField: "LinksTo",
checkboxes: {
checkChildren: true
},
dataTextField: ["notificationType", "NotificationDesc"],
select: treeviewSelect
});
function treeviewSelect(e)
{
var node = this.dataItem(e.node);
window.open(node.NotificationLink, "_self");
}
}
[HttpGet]
public List<Node> getNotifications(int id)
{
var bo = new HomeBO();
var list = bo.GetNotificationsForUser(id);
var notificationTreeNodes = (from GBLNotifications n in list
where n.NotificationCount != 0
select new NotificationTreeNode(n)).ToList();
var li = notificationTreeNodes.Select(no => new Node
{
notificationType = no.NotificationNode.NotificationType + " " + "(" + no.NotificationNode.NotificationCount + ")", notifications = bo.GetNotificationsForUser(id, no.NotificationNode.NotificationTypeId).Cast<GBLNotifications>().Select(item => new Notification
{
ID = item.NotificationId, NotificationDesc = item.NotificationDescription, Params = new List<NotificationParam>
{
new NotificationParam
{
ParamName = item.Param1, ParamVal = item.ParamValue1
},
new NotificationParam
{
ParamName = item.Param2, ParamVal = item.ParamValue2
},
new NotificationParam
{
ParamName = item.Param3, ParamVal = item.ParamValue3
},
new NotificationParam
{
ParamName = item.Param4, ParamVal = item.ParamValue4
},
new NotificationParam
{
ParamName = item.Param5, ParamVal = item.ParamValue5
},
},
ActionPageName = item.ActionPageName
}).ToList()
}).ToList();
li.ForEach(i => i.notifications.ForEach(x => x.SetNotificationLink()));
return li;
}

Categories