i am pretty new to ASP MVC 5 and after reading several tutorials I still cannot seem to implement a simple autocomplete feature. My issue is that the data that the View is receiving is [Object object] and I have no idea why. The number of fetched words is correct, the only problem is that it does not show "words" just [Object object].
So this is my model:
public class Vassal
{
public string Name { get; set; }
public string Type { get; set; }
public int ID { get; set; }
public class VassalDBContext : DbContext
{
public DbSet<Vassal> Vassals { get; set; }
}
}
This is my Controller (VassalControlller)
public JsonResult AutoComplete(string search)
{
var vassalNames = from m in db.Vassals
select m;
if (!String.IsNullOrEmpty(search))
{
vassalNames = vassalNames.Where(s => s.Type.Contains(search));
}
return Json(vassalNames, JsonRequestBehavior.AllowGet);
}
and this is my View
#model IEnumerable<webVassal.Models.Vassal>
#{
ViewBag.Title = "Search";
}
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags" />
</div>
<script type="text/javascript" >
$(function () {
$('#tags').autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("AutoComplete")',
dataType: "json",
contentType: 'application/json, charset=utf-8',
data: {
search: $("#tags").val()
},
success: function (data) {
response($.map(data, function (item) {
return {
label: item
};
}));
},
error: function (xhr, status, error) {
alert(error);
}
});
},
minLength: 1
});
});
</script>
I am using Jquery 2.1.1, jquery-ui.min.js and jquery.ui.widget.js
Also if I were to adapt the code above to use the Twitter bootstrap typeahead plugin, what would I need to do? I tried following the instructions on this link http://deanhume.com/home/blogpost/twitter-bootstrap-typeahead-and-asp-net-mvc---key-value-pairs/88 and I was getting a hasOwnProperty error.
I apologize for any format issues i am kind of new on posting code issues.
Any help is very much appreciated.
Thank you for your time
try to replace
return {
label: item
};
with
return {
label: item.Name
};
you are returning an array of Objects not strings, so you will need to access the Name property on each in your success clause.
i think you should ask the bookstrap typeahead question separately.
Related
I have an MVC 5 view with the following JavaScript which is getting an error after invoking an action method on a controller:
<script type="text/javascript">
$('#ddlvendors').change(function () {
var descHtml = "";
var vendorId = $(this).val();
$.ajax(
{
type: "POST",
data: { vendorId: vendorId },
url: '#Url.Action("PurchaseOrderVendor")',
datatype: "json",
success: function (aVendorObject) {
alert(aVendorObject.Name);
},
error: function (req, status, error) {
alert(error);
}
});
});
</script>
The controller action method is as follows:
[HttpPost]
public ActionResult PurchaseOrderVendor( int vendorId)
{
Vendor aVendor=VendorServices.GetVendor(vendorId);
return Json(aVendor);
}
The vendor object being returned is as follows:
public class VendorViewModel
{
public int VendorId { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Description { get; set; }
public string ContactName { get; set; }
public string Phone { get; set; }
}
Using the Visual Studio 2017 debugger I can see the vendor data is correctly getting filled on the controller side. If I don't try to access any member data the ajax call completes without an error. However, when I try to access any part coming in as aVendorObject such as aVendorObject.Name I get a browser error saying "Internal Server Error". How can I fix my success handler in the ajax call so I can access members of the Vendor object being returned from the controller?
Thanks in advance.
The LazyLoading feature of EntityFramework 6 did not have the Vendor object available when it was needed. I added a line in the VendorServices class to turn off LazyLoading which fixed the problem. Below is the method where I turn off LazyLoading for this particular VendorService method:
static public Vendor GetVendor(int aVendorId)
{
Vendor vendor;
using (RgmSiteDAL RgmSiteDALCtx = new RgmSiteDAL())
{
//** Now setting LazyLoadingEnabled to false.
RgmSiteDALCtx.Configuration.LazyLoadingEnabled = false;
vendor = RgmSiteDALCtx.Vendor
.Where(v => v.VendorId == aVendorId)
.FirstOrDefault<Vendor>();
}
return vendor;
}
I found out that I can also fix the problem if I include any navigation properties defined with the Vendor entity as in the following:
vendor = RgmSiteDALCtx.Vendor
.Where(v => v.VendorId == aVendorId)
.Include(v => v.PurchaseOrder) //because is in Vendor navigation property
.FirstOrDefault<Vendor>();
For my situation I will stick with the first solution which sets LazyLoadingEnabled to false. This is because the option to generate my entities from my existing database setup my PurchaseOrder table as a navigation property for my Vendor which I believe is incorrect. My Vendor object does not need anything from my PurchaseOrder entity when I query for Vendor information. I will look into removing the PurchaseOrder navigation property from my Vendor entity because I believe it was incorrectly setup by the create entities from database tool in Visual Studio.
my jquery script code part , the script is working fine and set data array/object in dataBLL..
var dataBLL = [];
$('#mytable tr').each(function (i) {
dataBLL.push({
id: $(this).find('td:eq(0)').text(),
ctype: $(this).find('td:eq(1)').text(),
cpath: $(this).find('td:eq(2)').text(),
ckey: $(this).find('td:eq(3)').text(),
ckey: $(this).find('td:eq(4) input:frist').val(),
});
$.ajax ({
url:"User/BllBtn",
type:"POST",
data:"dataBll="JSON.stringify(dataBLL);
dataType: "json",
success: function (e) {
alert("sucess");
}})
but i am not able to send this object/Array to my controller to use it's data and iterate through each row entry .
My controller signature
[HttpPost]
public ActionResutl BllBtn(List<string> dataBll)
{
}
Please guide how to get this object as list so I can loop into in simplest way.
You've got a syntax error (which your browser console will have told you), and also you're producing invalid JSON.
data: { "dataBll": dataBLL }
should work I think. Or
data: JSON.stringify({ "dataBll": dataBLL })
at worst. Also set
contentType: 'application/json; charset=UTF-8'
as another option in the ajax call.
The next problem is you are trying to accept List<string> into your method, but dataBll is a complex object with the following properties:
id, ctype, cpath, ckey, ckey
Firstly, you can't define ckey twice in the same object, and secondly your JSON object is incompatible with the type in the C# method. You need to define a class, e.g.
public class myNewType
{
public string id {get; set; }
public string ctype {get; set; }
public string cpath {get; set; }
public string ckey {get; set; }
}
and then accept List<myNewType> as the parameter to the method:
public ActionResult BllBtn(List<myNewType> dataBll)
I'm trying to post strings from an AngularJS application (using $http) to a server built on ASP.NET WebApi, but I get 404 as soon as I add a parameter.
The client code is this
$scope.add = function () {
// ...cut...
$http({ method: "POST", url: url, data: { fileString: "test string" }}).then(
function successCallback(response) {
$log.info(response.data);
}
);
}
The server code is
[HttpPost]
public IHttpActionResult UploadExcel(string fileString) {
// cut
}
I get a 404, but if I remove the parameter on server side it works, so i can use a server side code like this
[HttpPost]
public IHttpActionResult UploadExcel() {
// cut
}
What is wrong? Should I pass the data in a different way? I tried different combination but I can't get it work.
What you want to do is send a string, not a JSON object as you are doing right now with { fileString: "test string" }. When I want to send a string, what I normally do is that I send data from Angular like this:
$http.post("/Search/QuickSearch?searchQuery="+ searchString);
And my controller I make ready to receive a string like this:
[HttpPost]
public IHttpActionResult QuickSearch(string searchQuery)
{
// cut
}
If I want to send a JSON object, I tell my controller what it should expect, like this:
[HttpPost]
public IHttpActionResult SaveActivity(ActivityEditForm form);
{
// cut
}
public class ActivityEditForm
{
public int? Id { get; set; }
[Required]
public string Title { get; set; }
public string Description { get; set; }
}
And then send my JSON from Angular like this:
$http.post("/Activity/SaveActivity", { form: activity });
I suggest you should capture the request send by Angular. By default, Angular send parameters in a json string in request body.
I'm not sure wether Asp.net can parse them from json string in body.
So, you can try to add the below codes (also need jQuery)
angular.module('yourApp').config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data){
if (data === undefined) {
return data;
}
return $.param(data);
}
});
The first error is in the controller, [FromBody] should be used with the input parameter.
public IHttpActionResult UploadExcel([FromBody]string fileString)
Then the data variable on the client should be a single string, so
$http({ method: "POST", url: url, data: "test string" }).then(
Anyway I found some issue with this solution later, it seems the simplest but I suggest to avoid it.
Best solution
Thank to #Squazz answer and this SO answer I strongly suggest a change in the webapi controller, client was correct. Just introduce a class to handle a single string and adapt the input parameter
// new class with a single string
public class InputData {
public string fileString { get; set; }
}
// new controller
[HttpPost]
public IHttpActionResult UploadExcel([FromBody] InputData myInput) {
string fileString = myInput.fileString;
// cut
}
This way JSON code from the client is automatically parsed and it's easy to change the data input.
Extra tip
$scope.add angular function was correct as in the question, but here is a more complete example
$scope.testDelete = function () {
var url = "http://localhost/yourAppLink/yourControllerName/UploadExcel";
var data = ({ fileString: "yourStringHere" });
$http({ method: "POST", url: url, data: data }).then(
function successCallback(response) {
console.log("done, here is the answer: ", response.data);
}, function errorCallback(response) {
console.log("an error occurred");
}
);
}
I am trying to send multiple objects in js to a controller in C# using an Ajax call.
I have a object in C# called "Person"
which is the next :
public class Person
{
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
and I have the same object In JavaScript.
Then create two persons and I send to the controller.
This is the Ajax call
$.ajax({
url: baseUrl + "/controller/TestPeople",
type: "POST",
data: {
people: people
},
success: function (resp) {
alert("ok");
}
});
This is the post
people[0][Title]:"Mr."
people[0][FirstName]:"fname1"
people[0][LastName]:"Lname1"
people[0][Age]:23
people[1][Title]:"Mr."
people[1][FirstName]:"fname2"
people[1][LastName]:"Lname2"
people[1][Age]:25
but when i receive it in the controller, everything is null
public string TestPeople(Person[] people){
//some code
}
the controller knows that there are 2 people but all the information inside is null.
Any idea why?
To "solve" the problem i change the controller to use FormCollection and it is working, but i would like to know why the other is not working.
Thanks for all.
Try with:
data : JSON.stringify(peopleArray)
In your controller try:
public string Get(Person[] people){
//some code
}
I'm making an ASP.NET Web API web service, and an HTML/javascript page to test it. The issue I'm having is with passing a complex data parameter and having it come through properly in the web API controller.
I know there are numerous similar questions and I've read them and tried the solutions and haven't solved it. I have also read some JQuery documentation.
Here's my controller:
public class TitleEstimateController : ApiController
{
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
// Various fields
}
The route mapping in WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{query}"
);
And the javascript:
var uri = 'api/titleEstimate/';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri,query)
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
Currently I'm getting a 404. I tried $.getJSON(uri + '/' + query) but that didn't work either. Before I was passing this object I was calling it successfully so I think the routing is generally OK. I tried a type converter, but that didn't help, still a 404. Does anyone see what I'm missing/doing wrong?
Answer
You are using the wrong uri. You need api/titleEstimate/getTitleEstimate. That explains and will resolve your 404.
Answer to Follow Up Question
Everything else you're doing almost works. After you resolve the 404, you'll find that you aren't receiving the value FromUri, and you'll have a follow up question. So, you need to change your route config to this:
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{action}"
);
Then you'll not only resolve your 404 but also receive the FromUri value that you're sending as query string parameters.
Demo
Here is a fiddle for evidence, which is calling into this controller, which is hosted LIVE here. The only thing I changed in the working version are the uri to resolve the 404 and the route config to make sure you receive the FromUri value. That's all.
HTML
<label>Username:
<input id="user" />
</label>
<button id="submit">Submit</button>
<button id="submit-fail">Submit Fail</button>
<div id="product"></div>
JavaScript
This will succeed.
Note, we only need domain because we doing cross-site scripting here for the demo purpose.
var domain = "https://cors-webapi.azurewebsites.net";
$("#submit").click(function () {
var uri = domain + '/api/titleEstimate/getTitleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
This will 404.
$("#submit-fail").click(function () {
var uri = domain + '/api/titleEstimate';
var query = {
"username": $("#user").val(),
// other fields
};
$.getJSON(uri, query)
.done(function (data) {
$('#product').text(data);
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});
Controller
public class TitleEstimateController : ApiController
{
public class EstimateQuery
{
public string username { get; set; }
}
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
if(query != null && query.username != null)
{
return Ok(query.username);
}
else
{
return Ok("Add a username!");
}
}
}
You can read more details about WebApi routing here. From reading it you can probably come up with an alternative solution within your route config. There are also lots of terrific examples in this blog post.
First, I would try to use the attribute routing feature of web.api like this:
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
It would also be helpful to see the request in your dev tools. I disagree with Colin that you should make this a POST, because HTTP POST is supposed to be used to create new items. You are trying to get information so HTTP GET makes sense.
I think Web.Api assumes methods are GETs by default, but declarating it with the HttpGet attribute will for sure take care of that.
For complex objects, I usually send them in the message body rather than the URL.
Would you have any objection to an approach similar to the answer of this question?
How to pass json POST data to Web API method as object
It seems like the more straightforward/natural approach.
Something like (untested, but should be close):
[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
[HttpGet]
public IHttpActionResult GetTitleEstimate([FromBody] EstimateQuery query)
{
// All the values in "query" are null or zero
// Do some stuff with query if there were anything to do
}
}
public class EstimateQuery
{
public string QueryName{ get; set; }
public string Whatever{ get; set; }
}
$(function () {
var query = {QueryName:"My Query",Whatever:"Blah"};
$.ajax({
type: "GET",
data :JSON.stringify(query),
url: "api/titleEstimate",
contentType: "application/json"
})
.done(function (data) {
$('#product').text("OK");
})
.fail(function (jqXHR, textStatus, err) {
$('#product').text('Error: ' + err);
});
});