ASP.NET MVC Action Not Getting Parameter Values - javascript

I am working on an ASP.NET MVC 4 app. This app has a controller with an action that looks like the following:
public class MyController : System.Web.Http.ApiController
{
[ResponseType(typeof(IEnumerable<MyItem>))]
public IHttpActionResult Get(string id, string filter)
{
IEnumerable<MyItem> results = MyItem.GetAll();
List<MyItem> temp = results.ToList<MyItem>();
var filtered = temp.Where(r => r.Name.Contains(filter);
return Ok(filtered);
}
}
I am calling this action using the following JavaScript, which relies on the Select2 library:
$('#mySelect').select2({
placeholder: 'Search here',
minimumInputLength: 2,
ajax: {
url: '/api/my',
dataType: 'json',
quietMillis: 150,
data: function (term, page) {
return {
id: '123',
filter: term
};
},
results: function (data, page) {
return { results: data };
}
}
});
This code successfully reaches the controller action. However, when I look at id and filter in the watch window, I see the following errors:
The name 'id' does not exist in the current context
The name 'filter' does not exist in the current context
What am I doing wrong? How do I call the MVC action from my JavaScript?
Thanks!

You're not passing actual data as the parameters, you're passing a function:
data: function (term, page) {
return {
id: '123',
filter: term
};
}
Unless something invokes that function, the result will never be evaluated. Generally one would just pass data by itself:
data: {
id: '123',
filter: term
}
If, however, in your code there's a particular reason (not shown in the example) to use a function, you'll want to evaluate that function in order for the resulting value to be set as the data:
data: (function (term, page) {
return {
id: '123',
filter: term
};
})()
However, these errors also imply a second problem, probably related to however you're trying to debug this:
The name 'id' does not exist in the current context
The name 'filter' does not exist in the current context
Even if no values were being passed, id and filter still exist in the scope of the action method. They may be null or empty strings, but the variables exist. It's not clear where you're seeing that error, but it's definitely not in the scope of the action method.

Related

How to structure a JSON call

I have an endpoint which I call with Axios and the response looks like (for example):
items: [
{
url: "https://api.example1...",
expirationDate: "2019-11-15T00:00:00+01:00"
},
{
url: "https://api.example2...",
expirationDate: "2019-12-20T00:00:00+01:00"
},
{
url: "https://api.example3...",
expirationDate: "2020-01-17T00:00:00+01:00"
},
...and so on.
If I go to one of the url:s in the browser the structure of the JSON is:
fooBar: {
url: "https://api.foo...",
id: "123",
type: "INDEX",
source: "Foobar",
quotes: {
url: "https://api.bar..."
}
},
I need to get the quotes of the two first url:s in items:[] dynamically because they will disappear when the 'expirationDate' is older than today's date.
How can this be achieved? Thanks in advance!
If I understand the requirements correctly you need to:
get the list of items
get item details for first two items (to extract links to quotes)
get quotes for first two items
You can use promise chaining to execute these operations maintaining the order:
const getQuotes = (item) => axios.get(item.url)
.then(resp => axios.get(resp.data.fooBar.quotes.url));
axios.get('/items') // here should be the url that you use to get items array
.then(resp => resp.data.slice(0, 2).map(getQuotes))
.then(quotes => Promise.all(quotes))
.then(quotes => {
console.log(quotes);
});
Please find my proposal below. I gave two examples. You can get the whole quotes object, or just the URL inside the quotes object.
This is just a console log, but you can easily ie. append this data to a div in the html or pass this URL to some other function.
$(function() {
const address = 'https://api.example1...';
function loadQuotes() {
$.ajax({
url: address,
dataType: 'json',
}).done(function(response) {
response.forEach(el => {
console.log(`el.quotes`);
// or if you want to be more specific console.log(`el.quotes.url`);
});
});
}
loadQuotes();
});
If these are nested objects, just append fooBar.
For example change the .done part to:
.done(function(response) {
let qqq = response.quotes
quotes.forEach(el => {
console.log(`el.quotes`);
// or if you want to be more specific console.log(`el.quotes.url`);
});

Pass list of items from $.get() to MVC controller

My controller Action method looks like the below:
[HttpGet]
[Route("ShowModal")]
public Task<IActionResult> GetDetails(int id, string name, IEnumerable<Employee> employees)
{
//create a model
//Some business logic codes
return PartialView("_Partial.cshtml", model);
}
I need to call the above Action Method from jQuery's $.get() method on a button click, capture the partial view returned as HTML, and show it in a Bootstrap popup.
I am not able to pass the IEnumerable<Employee> from the jQuery method, it is always null, whatever I try.
Below is the JS code:
<a class="btn btn-primary" onclick="ShowModal();" data-keyboard="true" data-toggle="modal">ShowModal</a>
<div class="modal fade" id="divShowModalDialog" role="dialog" tabindex="-1">
<div class="modal-body" id="divShowModalBody">
</div>
</div>
function ShowModal()
{
var list = [{ Id: 101, Gender: 'MALE' }, { Id: 102, Gender: 'FEMALE' }];
list = JSON.stringify(list);
var data = { 'id': 999, 'name': 'JAMES', 'employees': list };
$.get('/Area1/Controller1/ShowModal', data)
.done(function (response) {
if (response != undefined) {
$('#divShowModalBody').html(response);
$('#divShowModalDialog').modal(
{
backdrop: 'static',
keyboard: true,
});
}
})
.fail(function (xhr) {
console.log(xhr);
})
}
I get the id and name parameter in the Action method, but the list is always empty. I have tried after removing JSON.stringify() as well, but it doesn't work.
I know I'm missing a trivial thing, please help.
First, you should be using [HttpPost] on your controller action and not [HttpGet], and of course you'll need to use post from jQuery which is using $.post() and that is because 'POST' is the correct - but not the only - HTTP verb to actually post data to the server side.
Second, you shouldn't stringify your employees list before you put it in your data javascript object that you are sending.
so, list = JSON.stringify(list); and just straight away go
var data = { 'id': 999, 'name': 'JAMES', 'employees': list };
You also might need to provide the dataType using $.post(url,data,onsucess,dataType) check documentation in the link above.
Last, on your action method remove IEnumerable<T> and replace it with a concrete collection type like List<T> because the JSON serializer will need to know which type of collection to instantiate at binding time.
Actually you can achieve it without changing it to POST by using $.ajax()
Use a dictionary object instead of IEnumerable in action method
public ActionResult GetDetails(int id, string name, Dictionary<int,string> employees)
{
And then in the script
var list = [{ Id: 101, Gender: 'MALE' }, { Id: 102, Gender: 'FEMALE' }];
var data = { id: 999, name: 'JAMES', employees: list };
debugger;
$.ajax({
url: '/Home/GetDetails',
type: "GET",
data :data,
contentType: "application/json",
dataType: "json"
});
I was replying to your comment but decided it would be easier to demonstrate my point as an answer.
To answer your question, no I am not sure. But thats why I asked you to try it first, it seems logical as you are passing a list and not IEnumerable to your function.
Also, depending on what your Employee class looks like, you should try this: (you need a constructor in your Employee class for this)
List<Employee> list = new List<Employee>();
list.Add(new Employee(101, 'MALE'));
list.Add(new Employee(102, 'FEMALE'));
var data = { 'id': 999, 'name': 'JAMES', 'employees': list };
...
Update
I realize why I'm wrong, I kept thinking in C# terms. Json.stringify() returns a json style string (which C# just sees as a string), so your public Task GetDetails(int id, string name, IEnumerable employees) should be public Task GetDetails(int id, string name, string employees) and then in C#, you need to parse the JSON string. A helpful link:
How can I parse JSON with C#?

Select2 Multiple format to be passed to JSON

I am using the select2 multiple for search box. I am passing these data with JSON and saving it using ajax(JSON stringify).
I just need 2 variables passed, which is the ID(primary key, customized) and the Selection itself.
I managed to save it to the database when only 1 value is selected.
When selecting multiple values, in my console.log, I see something like this
{21,23,25,26}
which is the selection itself.
How do I get it show like this,
Object0->{id:1, selection:21}
Object1->{id:2, selection:23}
Object2->{id:3, selection:25}
Object3->{id:4, selection:26}
Below is the code I am using,
var nature = {
ubtBusinessInfo: businessId, // the primary key
ubtBusinessListing: nature.val() // here is selection
};
Here is the initialization of the select2,
nature
.select2({
allowClear: true,
placeholder: "Filter as you type",
minimumInputLength: 3,
multiple: true,
ajax: {
url: 'home/umkei/info/nature',
dataType: 'json',
quietMillis: 250,
data: function (term, page) {
return { q: term };
},
results: function (data, page) {
return { results: data };
},
cache: true
}
})
nature is defined from(I tried both as below)
var nature = $('[name=nature_business]') OR var nature = $(#nature_business);
I know it must have something to do with the nature.val() usage. Must have been something like array but I dont know how to differentiate/split those data to be key->value pairs.
Thank you.
I got this about last week and thought I'd share my solution.
var nature=[];
var splitnature = nature_business.val().trim().split(',');
var n;
for(n=0; n<=splitnature.length-1;n++){
nature.push({
ubtBusinessListing: splitnature[n],
ubtBusinessInfo: businessId
});
}

Select2 js Plugin Not able to select any option

I am using Select2.js(latest version) to implement tokenized tagging in my application. It is working fine except, I am not able to select any item from the suggestions.
I saw few answers in which it was mentioned that we need to include "id" in our configuration. it doesn't seems to be working for me.
My code is :
$("#interest").select2({ ajax: {
url: "get-interests",
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},
processResults: function (data, page) {
// parse the results into the format expected by Select2.
// since we are using custom formatting functions we do not need to
// alter the remote JSON data
return {
results: data
};
},
cache: true
},
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
placeholder:{
id: "-1",
text: "Add your interest.."
} ,
tags: true,
tokenSeparators: [',', ' '],
id: function(data) {
alert(JSON.stringify(data));
return data.interestId;
},
templateResult: function(post) {
// return html markup for individual result item
var markup ="";
if(String(post.description) !== 'undefined') {
markup = '<p><b>' + post.text + '</b> : ' + post.description + '</p>';
} else {
markup = '<p><b>' + post.text + '</b></p>';
}
return markup;
},
formatSelection: function(post) {
// This shows up in the select box
return post.text;
}
What I am doing wrong in above configuration?
Contrary to the comment you placed in your code, with Select2 4.0 you do need to add code to the processResults function to convert the returned JSON data to objects with an id property. Normally, the objects should also have a text property, but they don't have to if you supply the templateResult and templateSelection functions.
I saw few answers in which it was mentioned that we need to include
"id" in our configuration. it doesn't seems to be working for me.
Those answers were correct for previous versions of Select2, but with with Select2 v4.0, the id function is no longer supported. See the "The id and text properties are strictly enforced" section on the the "4.0 Anouncement" page:
You can also remove the formatSelection function. With Select2 4.0 it should now be named templateSelection. That means it is not getting called for you, but you probably didn't notice that because your formatSelection function is just doing what is done by default anyway.
The processResults function should return an object with a results property, which is set to an array of objects. Those objects all need to have an id property (but they can have other properties too).
You don't show what your returned data looks like, but judging from your id and templateResult functions, it appears to be an array of objects with the following properties: interestId, text and description. In that case your processResults function could look something like this:
// This builds a new array of new objects.
processResults: function(data, page) {
return {
results: $.map(data, function(post) {
return {
id: post.interestId,
text: post.text,
description: post.description
};
})
};
},
Or this:
// This just adds an `id` property to the objects in the existing array.
processResults: function(data, page) {
$.each(data, function(i, post) {
post.id = post.interestId;
});
return { results: data };
},

AngularJS $resource passes id as query parameter instead in url

I need to GET data from a rest API, with the product id part of the url (and not as query parameter).
The factory:
.factory('Products', ['$resource',
function($resource) {
return $resource('products/:productId', {
productId: '#id'
}, {
query: {
isArray: false
},
update: {
method: 'PUT'
}
});
}
])
The controller:
$scope.getProduct = function(id, from) {
$scope.product = Products.get({ id: id }, function(){
console.log($scope.product);
});
}
My url is constructed like:
/products?id=5426ced88b49d2e402402205
instead of:
/products/5426ced88b49d2e402402205
Any ideas why?
When you call Products.get() in the controller, you are not using the correct parameter name (you need to use "productId" instead of "id" based on your definition of the $resource). Try calling it like this instead:
Products.get({ productId: id })
Here is a snippet from the documentation for $resource which explains how it works:
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
In your case, it's not finding "id" as a parameter in the URL, so it adds that to the query string.

Categories