jqueryui autocomplete render HTML returned by server - ajax

I have a simple page with an input text-box. The text box is bound to jquery ui autocomplete that makes an AJAX call to the server. My server side code is an ASP.NET MVC site. The only difference I have as compared to most examples found over the Internet is that my Server side code returns a PartialView (html code) as results instead of JSON. I see the AJAX call happening and I see the HTML response in the AJAX success event as well.
My question is how do I bind this HTML data to show in the AutoComplete?
The code I have so far is:
$("#quick_search_text").autocomplete({
minLength: 3,
html: true,
autoFocus: true,
source: function (request, response) {
$.ajax({
type: "POST",
url: "serversideurl",
data: "{ 'SearchTerm': '" + request.term + "', 'SearchCategory': '" + $("#quick_search_category").val() + "' }",
contentType: "application/json; charset=utf-8",
dataType: "html",
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
},
success: function (data) {
//THIS IS WHERE MY HTML IS RETURNED FROM SERVER SIDE
//HOW DO I BIND THIS TO JQUERY UI AUTOCOMPLETE
}
});
},
select: function (event, ui) {
},
response: function (event, ui) {
console.log(ui);
console.log(event);
}
});

This works:
1) Create an action in your controller and set the RouteConfig to start this action
public class HomeController : Controller
{
public ActionResult Index20()
{
MyViewModel m = new MyViewModel();
return View(m);
}
Create a view without any type of master page
Add this view model:
public class MyViewModel
{
public string SourceCaseNumber { get; set; }
}
Go to Manage Nuget Packages or PM Console and add to MVC 5 project - Typeahead.js for MVC 5 Models by Tim Wilson
Change the namespace for the added HtmlHelpers.cs to System.Web.Mvc.Html and rebuild
Add this class:
public class CasesNorm
{
public string SCN { get; set; }
}
Add these methods to your controller:
private List<Autocomplete> _AutocompleteSourceCaseNumber(string query)
{
List<Autocomplete> sourceCaseNumbers = new List<Autocomplete>();
try
{
//You will goto your Database for CasesNorm, but if will doit shorthand here
//var results = db.CasesNorms.Where(p => p.SourceCaseNumber.Contains(query)).
// GroupBy(item => new { SCN = item.SourceCaseNumber }).
// Select(group => new { SCN = group.Key.SCN }).
// OrderBy(item => item.SCN).
// Take(10).ToList(); //take 10 is important
CasesNorm c1 = new CasesNorm { SCN = "11111111"};
CasesNorm c2 = new CasesNorm { SCN = "22222222"};
IList<CasesNorm> aList = new List<CasesNorm>();
aList.Add(c1);
aList.Add(c2);
var results = aList;
foreach (var r in results)
{
// create objects
Autocomplete sourceCaseNumber = new Autocomplete();
sourceCaseNumber.Name = string.Format("{0}", r.SCN);
sourceCaseNumber.Id = Int32.Parse(r.SCN);
sourceCaseNumbers.Add(sourceCaseNumber);
}
}
catch (EntityCommandExecutionException eceex)
{
if (eceex.InnerException != null)
{
throw eceex.InnerException;
}
throw;
}
catch
{
throw;
}
return sourceCaseNumbers;
}
public ActionResult AutocompleteSourceCaseNumber(string query)
{
return Json(_AutocompleteSourceCaseNumber(query), JsonRequestBehavior.AllowGet);
}
credit goes to http://timdwilson.github.io/typeahead-mvc-model/

Related

return partial view from async method

I've an async action method that return a partial view.
this action method called from a function with ajax.
my problem : when this method invoked every thing looks good except returned partial view.
I got error 500.
this is my action method Code :
[HttpPost]
public async Task<ActionResult> ChangeStateGroup(int[] lstCustomerServiceId, int newState)
{
int _counter = 0;
try
{
var _isOk = await CommonFunctions.ChangeState(_customerServiceId, _stateId, string.Empty);
if (_isOk)
{
//------do somthing
}
}
TempData[MyAlerts.SUCCESS] = string.Format("succeed Operation {0}", _counter);
}
catch (Exception ex)
{
TempData[MyAlerts.ERROR] = string.Format("Error: {0}", ex.Message);
}
return PartialView("_AlertsPartial");
}
and this is my jquery Code:
function postCustomerChangeStateGroup(lstCustomersId) {
var arrCustomersId = lstCustomersId.split(',');
$.ajax({
type: "POST",
url: "../Customer/ChangeStateGroup",
data: {
lstCustomerServiceId: arrCustomersId,
newState: $("#fk_state").val()
},
success: function (data) {
if (data.indexOf("error") !== -1) {
$("#inlineAlert_Wrapper").append(data);
}
else {
getCustomerReport();
$('#modal-container').modal('toggle');
$("#alert_Wrapper").append(data);
}
},
failure: function (errMsg) {
alert("An Error Accoured: " + errMsg);
}
});
}
Partial views cannot be asynchronous in ASP.NET pre-Core. You can have asynchronous partial views in ASP.NET Core.
So, your options are:
Update to ASP.NET Core.
Remove the asynchronous code and make it synchronous instead.
Error 500 means the error inside of the action.It maybe because ot the empty input parameters. Check them in debugger and if they are empty,
try to use application/json content type,sometimes it works better
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Customer/ChangeStateGroup",
data: JSON.stringify( {
lstCustomerServiceId: arrCustomersId,
newState: $("#fk_state").val()
}),
success: function (data) {
....
create viewModel
public class ViewModel
{
public int[] lstCustomerServiceId {get; set;}
public int newState {get; set;}
}
and fix the action
public async Task<ActionResult> ChangeStateGroup([FromBody] ViewModel model)

Session not retaining TempData through multiple Ajax calls to Controller

Im trying to work with an object (VideoInfo) in several Action methods. A form sends a viewmodel with a video file to the Upload method in VideoController. It uploads the video and returns a generated guid. When the callback has returned, a new ajax call is made to the Convert method which returns the guid. As seen in the javascript part of Create.cshtml it makes two other Ajax calls, one to the Progress method and one to the Azure method.
When trying to fetch the VideoInfo object in the Azure method and the Progress method, videoInfo is null. Though it successfully retains the data between the Upload method and Convert method. Im using TempData.Peek() so that it shouldnt mark it for deletion.
I can see that the Upload and Convert method is using the same instance of VideoController, where as the Progress and Azure method uses another instance, I guess this could have to do with the problem.
InstanceId when running Upload method: 23ef96fa-c746-4722-ad07-e9e40fc95f29
InstanceId when running Convert method: 23ef96fa-c746-4722-ad07-e9e40fc95f29
InstanceId when running Progress method: 0aba24b2-ccb8-434d-a27d-cc66cb52c466
InstanceId when running Azure method: 0aba24b2-ccb8-434d-a27d-cc66cb52c466
How can I retain data between my Ajax calls in the VideoController?
Why is the instance id same for the first two calls but then it changes?
VideoController.cs
using System;
namespace MediaPortal.Controllers
{
[Authorize(Roles = "Admin")]
public class VideoController : Controller
{
private static Guid InstanceId { get; }
static VideoController()
{
InstanceId = Guid.NewGuid();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(CreateVideoViewModel model)
{
if (ModelState.IsValid)
{
if (model.File != null)
{
Debug.WriteLine("Upload method InstanceId: " + InstanceId.ToString());
// ...
TempData[videoInfo.Id] = videoInfo;
videoInfo.cvvm.File.SaveAs(videoInfo.TempPath);
return Json(new { Successfull = true, Id = videoInfo.Id });
}
return null;
}
return null;
}
[HttpPost]
public ActionResult Convert(string id)
{
Debug.WriteLine("Convert method InstanceId: " + InstanceId.ToString());
// Create new object of FFMpegConvertor
var converter = new FFMpegConverter();
VideoInfo videoInfo = (VideoInfo)TempData.Peek(id);
// ...
return Json(new { Successfull = true, Id = videoInfo.Id });
}
[HttpPost]
public ActionResult Azure(string id)
{
Debug.WriteLine("Azure method InstanceId: " + InstanceId.ToString());
VideoInfo videoInfo = (VideoInfo)TempData[id];
// ...
if (videoUpload != null && thumbnailUpload != null)
{
Video video = new Video
{
Id = videoInfo.Id.ToString(),
Name = videoInfo.cvvm.Name,
ProjectId = videoInfo.cvvm.ProjectId,
Type = "mp4",
VideoUri = videoUpload.Uri.ToString(),
ThumbnailUri = thumbnailUpload.Uri.ToString()
};
db.Videos.Add(video);
db.SaveChanges();
return Json(new { Successful = true, Data = Url.Action("Index", new { projectId = videoInfo.cvvm.ProjectId }) });
}
return null;
}
[HttpPost]
public JsonResult Progress(string id)
{
Debug.WriteLine("Progress method InstanceId: " + InstanceId.ToString());
try
{
VideoInfo videoInfo = (VideoInfo)TempData.Peek(id);
return Json(new { Data = videoInfo.Progress });
}
catch
{
return Json(new { Data = "No Video Information in Dictionary for Id: " + id });
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
Create.cshtml (JQuery/Ajax)
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<script>
$.noConflict();
jQuery(document).ready(function ($) {
var bar = $('.progress-bar');
var percent = $('.percent');
$('#Myform').ajaxForm({
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function () {
var percentVal = '0%';
bar.width(percentVal);
percent.html(percentVal);
},
uploadProgress: function (event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal);
percent.html(percentVal);
},
complete: function (uploadStatus) {
console.log("Upload finished for video with Id: " + JSON.parse(uploadStatus.responseText).Id);
setTimeout(function () { progress(uploadStatus) }, 1000);
$.ajax({
type: "POST",
url: '#Url.Action("Convert", "Video")?id=' + JSON.parse(uploadStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (convertStatus) {
console.log("Conversion finished for video with Id: " + JSON.parse(convertStatus.responseText).Id);
$.ajax({
type: "POST",
url: '#Url.Action("Azure", "Video")?id=' + JSON.parse(convertStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (azureStatus) {
window.location.href = JSON.parse(azureStatus.responseText).Data;
}
});
}
});
}
});
function progress(uploadStatus) {
$.ajax({
type: "POST",
url: '#Url.Action("Progress", "Video")?id=' + JSON.parse(uploadStatus.responseText).Id,
dataType: "json",
contentType: "application/json; charset=utf-8",
complete: function (progressStatus) {
console.log("Progress: " + JSON.parse(progressStatus.responseText).Data);
if (JSON.parse(progressStatus.responseText).Data < 100) {
setTimeout(function () { progress(uploadStatus) }, 1000);
}
else if (JSON.parse(progressStatus.responseText).Data >= 100) {
console.log("Video Conversion Completed");
}
else {
console.log("Something went wrong");
}
}
})
}
});
</script>
It seems IIS Express was the problem. I cant say why though. I realized this because when I deployed the project to my production server in Azure it all worked fine.
So instead of using IIS Express I installed IIS on my development machine, works perfectly after that.

ajax calls the mvc controller

why this code does not work?.I receive "ok" but i can not see the view1 (view1 not loaded).I want to manage the views by prop1 .If the value of prop1="1" load view1
Hier is my controller
[System.Web.Mvc.Route("Home/SubmitMyData/")]
[System.Web.Http.HttpPost]
public ActionResult SubmitMyData([FromBody]MyParamModel mydata)
{
if (mydata.Prop1.Equals("1"))
return View("veiw1");
else
return View("view2");
}
public class MyParamModel // #4
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
and it is my ajax call
$('#Buttonv').click(function () {
var myData = {Prop1: "1", Prop2: ""}; // #1
$.ajax({
type: 'POST',
data: myData, // #2
url: '/Home/SubmitMyData',
})
.success(function (data) {
var output = "ok";
$('#lblmessage').html(output);
})
.error(function (xhr, ajaxoption, thrownError) {
$('#lblmessage').html("moshkelo" + xhr + "ajaxoption= " + ajaxoption + " throwerror=" + thrownError);
});
//return false;
});
If you are returning a View from your Controller, you'll need to ensure that you are actually using the HTML content within the success callback of your POST :
.success(function (data) {
// data will contain your content
$('#lblmessage').html(data);
})
You were previous using output, which didn't seem to be defined anywhere within your script.
Additionally, you may want to check the name of the view that you are returning as return View("veiw1"); seems like a typo that should be return View("View1");.
In your javascript, you are ignoring the HTML returned by the server. Try changing it to...
.success(function (data) {
$('#lblmessage').html(data);
})
Per the documentation, the first parameter to the success method is the data returned by the server.

HttpPost with AJAX call help needed

what else do i need in my code please, I have this so far:
<script type="text/javascript">
function PostNewsComment(newsId) {
$.ajax({
url: "<%= Url.Action("AddCommentOnNews", "Home", new { area = "News" }) %>?newsId=" + newsId + "&newsComment=" + $("#textareaforreply").val(), success: function (data) {
$("#news-comment-content").html(data + $("#news-comment-content").html());
type: 'POST'
}
});
}
$("#textareaforreply").val("");
</script>
and
[HttpPost]
[NoCache]
public ActionResult AddCommentOnNews(int newsId, string newsComment)
{
if (!String.IsNullOrWhiteSpace(newsComment))
{
var currentUser = ZincService.GetUserForId(CurrentUser.UserId);
ZincService.NewsService.AddCommentOnNews(newsId, newsComment, currentUser.UserId);
Zinc.DataModels.News.NewsCommentsDataModel model = new DataModels.News.NewsCommentsDataModel();
var today = DateTime.UtcNow;
model.CommentDateAndTime = today;
model.NewsComment = newsComment;
model.Firstname = currentUser.Firstname;
model.Surname = currentUser.Surname;
model.UserId = CurrentUser.UserId;
return View("NewsComment", model);
}
return null;
}
<div class="actions-right">
<%: Html.Resource(Resources.Global.Button.Reply) %>
</div>
i have no idea how this works, because it is not working in FF???
and the other thing is i must not pass return null i must pass JSON false ???
any help please?
thanks
You should encode your request parameters. Right now you have concatenated them to the request with a strong concatenation which is a wrong approach. There's a property called data that allows you to pass parameters to an AJAX request and leave the proper url encoding to the framework:
function PostNewsComment(newsId) {
$.ajax({
url: '<%= Url.Action("AddCommentOnNews", "Home", new { area = "News" }) %>',
type: 'POST',
data: {
newsId: newsId,
newsComment: $('#textareaforreply').val()
},
success: function (data) {
$('#news-comment-content').html(data + $('#news-comment-content').html());
}
});
}
Also you haven't shown where and how you are calling this PostNewsComment function but if this happens on the click of a link or submit button make sure that you have canceled the default action by returning false, just like that:
$('#someLink').click(function() {
PostNewsComment('123');
return false;
});
and the other thing is i must not pass return null i must pass JSON false ???
You could have your controller action return a JsonResult in this case:
return Json(new { success = false });
and then inside your success callback you could test for this condition:
success: function (data) {
if (!data.success) {
// the server returned a Json result indicating a failure
alert('Oops something bad happened on the server');
} else {
// the server returned the view => we can go ahead and update our DOM
$('#news-comment-content').html(data + $('#news-comment-content').html());
}
}
Another thing you should probably be aware of is the presence of dangerous characters such as < or > in the comment text. To allow those characters I would recommend you build a view model and decorate the corresponding property with the [AllowHtml] attribute:
public class NewsViewModel
{
public int NewsId { get; set; }
[AllowHtml]
[Required]
public string NewsComment { get; set; }
}
Now your controller action will obviously take the view model as argument:
[HttpPost]
[NoCache]
public ActionResult AddCommentOnNews(NewsViewModel viewModel)
{
if (!ModelState.IsValid)
{
var currentUser = ZincService.GetUserForId(CurrentUser.UserId);
ZincService.NewsService.AddCommentOnNews(viewModel.NewsId, viewModel.NewsComment, currentUser.UserId);
var model = new DataModels.News.NewsCommentsDataModel();
var today = DateTime.UtcNow;
model.CommentDateAndTime = today;
model.NewsComment = newsComment;
model.Firstname = currentUser.Firstname;
model.Surname = currentUser.Surname;
model.UserId = CurrentUser.UserId;
return View("NewsComment", model);
}
return Json(new { success = false });
}

Removing a Partial View in MVC

I have a View with Name, CreatedDate, Address, etc. In the Address section I have State, City etc. I made this section a Partial View.
By default there will be one address section in mainView. I have a button "AddAddress". I want to add another address section if user clicks the button (add a partial view). After getting this partial view there should be a remove button to remove this partial view. I am not using Razor.
the following code is my Javascript to delete my address.
function deleteAddress(addressId, clientId) {
var url1 = "/Client/DeleteAddress";
if (confirm("Are you sure you want to delete this address?")) {
var result = false;
$.ajax({
url: url1,
type: 'POST',
async: false,
data: { AddressId: addressId, ClientId: clientId },
dataType: 'json',
success: function (data) {
result = data;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("XMLHttpRequest=" + XMLHttpRequest.responseText + "\ntextStatus=" + textStatus + "\nerrorThrown=" + errorThrown);
}
});
if (result) {
}
}
}
the following code is in my controller.
[HttpPost]
public JsonResult DeleteAddress(int AddressId, int ClientId)
{
if (AddressId != 0)
{
if (ClientId != 0)
{
ClientService.Client clientVuTemp = new ClientService.Client();
clientVuTemp = (ClientService.ClientView)TempData["EditClientData"];
clientVuTemp.Address.RemoveAt(AddressId);
//soft delete
clientVuTemp.Address[AddressId].IsActive = false;
_clientSvc.InserOrUpdateClientAddresses(clientVuTemp.Address);
}
else
{
}
return Json(true);
}
else
return Json(false);
}
In the Model we can have a property like IsAddAddressEnabled, Onclick on AddAddress you can set this as true and onclick on cancel you can set as false.
In View you can put an condition,
#if(Model.IsAddAddressEnabled)
{
Html.Partail(....)
}

Resources