I have two user controls on the page and one of the user control has this text aread.
which is used to add a note and but when they click add note button the page reloads.
I do not want the page to reload ,i was looking for an example which this is done without
postback.
Thanks
i tired doing this using JSON , but it throws the following error
The HTTP verb POST used to access path '/Documents/TestNote/Documents/AddNote' is not allowed.
<script type="text/javascript">
$(document).ready(function() {
$("#btnAddNote").click(function() {
alert("knock knock");
var gnote = getNotes();
//var notes = $("#txtNote").val();
if (gnote == null) {
alert("Note is null");
return;
}
$.post("Documents/AddNote", gnote, function(data) {
var msg = data.Msg;
$("#resultMsg").html(msg);
});
});
});
function getNotes() {
alert("I am in getNotes function");
var notes = $("#txtNote").val();
if (notes == "")
alert("notes is empty");
return (notes == "") ? null : { Note: notes };
}
</script>
</asp:Content>
Something like this would give you the ability to send data to an action do some logic and return a Json result then you can update your View accordingly.
Javascript Function
function AddNote(){
var d = new Date(); // IE hack to prevent caching
$.getJSON('/MyController/MyAction', { data: "hello world", Date: d.getTime() }, function(data) {
alert(data);
// call back update your view here
});
}
MyController Action
public virtual JsonResult MyAction(string data)
{
// do stuff with your data here, which right now my data equals hello world for this example
return Json("ReturnSomeObject");
}
What you want is AJAX update. There will always be a postback (unless you are satisfied with simple Javascript page update that does not save on the server), but it won't be the flashing screen effect any more.
Related
I am passing a complex model to a Razor View. The data in the model is used in a for-each loop in the view to display a list of products that are for sale in bootstrap cards. There are no forms on the view.
On the left side of the page are list elements that contain nested list elements. These represent product categories. When the user selects a category, I pass the product category to an action method in the controller as an integer. This will build a new model based on the selected category. The new model is then passed back to the view.
At this point, I want to display the categories that are in the category that the user selected. But, the view is not updating even though the model is now different.
I have been reading about this issue, and one forum post I read suggested that this is by design. I read somewhere that in order to achieve what I need to achieve, I have to clear the model state. But I cannot clear the model state because I am not passing the model back to the controller, and you can only pass the model back to the controller by reconstructing the model to be passed in an ajax call for example. I spent all day yesterday trying to get ajax to work and every time I executed the post, the model was populated in the JavaScript function and null or empty in the controller.
Is there another way to force the view to update upon sending a new model to the view? Does anyone have any suggestions?
<script type="text/javascript">
function AddSubCategory(elem) {
event.stopPropagation();
var e = document.querySelectorAll(".products");
e.forEach(box => {
box.remove();
});
var categoryId= $(elem).data('sub-id');
console.log(`Id: ${categoryId}`);
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
}
if (request != null) {
var url = `/Products/GetProductsByCategory?categoryId=${categoryId}`;
request.open("POST", url, false);
};
//request.onreadystatechange = function () {
// if (request.readyState == 4 && request.status == 200) {
// }
//};
request.send();
// model = JSON.stringify(model);
// console.log(model);
// $.ajax({
// type: "Post",
// url: '#Url.Action("GetProductsByCategory", "Products")',
// data: JSON.stringify({"categoryId": categoryId}),
// contentType: 'charset=utf-8;application/json',
// cache: false,
// complete: function (data) {
// }
//});
}
// Load all products
public async Task<IActionResult> Index()
{
ReadCartIDFromCookie();
string SubDomain = GetSubDomain(HttpContext);
var allProducts = await _productService.GetAllProductsWithImagesAsync(SubDomain);
var productCategoryLookup = await _productService.GetAllProductCategoryLookupAsync();
ViewBag.host = SubDomain;
ViewBag.productCategoryLookup = productCategoryLookup;
return View("Index", allProducts);
}
//Load filtered list of products
[HttpPost]
public async Task<IActionResult> GetProductsByCategory(int categoryId = -1)
{
ReadCartIDFromCookie();
string SubDomain = GetSubDomain(HttpContext);
var allProducts = await _productService.GetAllProductsWithImagesAsync(SubDomain, categoryId);
var productCategoryLookup = await _productService.GetAllProductCategoryLookupAsync();
ViewBag.host = SubDomain;
ViewBag.productCategoryLookup = productCategoryLookup;
return View("Index", allProducts);
}
I was able to resolve my issue thanks to this post: https://stackoverflow.com/a/66277911/1561777
I did have a bit of trouble trying to figure it out because it was not completely clear, but I could tell it was what I needed to do. I ended up utilizing a partial view for the display of my products. Here is my final code.
//My index.cshtml razor view
<div class="col" id="product"></div>//partial view will be loaded onto this div
//Javascript function that gets the chosen filter category Id
#section Scripts
{
<script type="text/javascript">
function AddSubCategory(elem) {
event.stopPropagation();
//get the id
var categoryId= $(elem).data('sub-id');
console.log(`Id: ${categoryId}`);
//call controller Products, controller action GetProductsByCategory and pass the categoryId
//The partial view will be returned and load onto the div id #product
$('#product').load(`/Products/GetProductsByCategory?categoryId=${categoryId}`);
}
//when the index view first loads, load all products (i.e. category -1)
$('#product').load(`/Products/GetProductsByCategory`);
</script>
}
public async Task<IActionResult> GetProductsByCategory(int categoryId = -1)
{
ReadCartIDFromCookie();
string SubDomain = GetSubDomain(HttpContext);
var allProducts = await _productService.GetAllProductsWithImagesAsync(SubDomain, categoryId);
var productCategoryLookup = await _productService.GetAllProductCategoryLookupAsync();
ViewBag.host = SubDomain;
ViewBag.productCategoryLookup = productCategoryLookup;
//notice that I am using PartialView method
//Returning View was including the full website (i.e. header and footer).
//_Products is my partial view. allProducts is the
//view model that is being passed to the partial view.
return PartialView("_Products", allProducts);
}
Now, everytime I select a new category, the partial view is reloaded. Also, when first loading the view, all products are displayed as expected.
I have a dropdownlist in my razor view MVC like
#Html.DropDownListFor(n => n.EMP_ID, (SelectList)ViewBag.EmployeeList, new { #id = "ddlemployee" },"---choose an Employee Name--").
I have applied select change event to drop-down using jquery, when select Employee name getting Employee names and realted data, but problem is when i select a value in drop-down, dropdownlist setting again set to default first value,
It is not sticking to particular selected value, in terms of Asp.net terminology, how to prevent postback to dropdownlist?
//Redirected to Controller
<script>
$(document).ready(function () {
$("#ddlemployee").change(function () {
location.href ='#Url.Action("GetEmployeeDetails", "Employer")'
});
});
</script>
//Action Method in Employer Controller
public ActionResult GetEmployeeDetails(Timesheetmodel model)
{
try
{
ViewBag.EmployeeList = objts.getEmployeeNames();
var emps = from n in db.TIMESHEETs
where n.RES_ID == model.EMP_ID
select n;
int count = emps.Count();
foreach (TIMESHEET ts in emps)
{
model.PROJ_ID = ts.PROJ_ID;
model.SUN_HRS = ts.SUN_HRS;
model.MON_HRS = ts.MON_HRS;
model.TUE_HRS = ts.TUE_HRS;
model.WED_HRS = ts.WED_HRS;
model.THU_HRS = ts.THU_HRS;
model.FRI_HRS = ts.FRI_HRS;
model.SAT_HRS = ts.SAT_HRS;
}
}
catch (Exception ex)
{
throw ex;
}
return View("Timesheet", model);
}
ASP.Net Webforms achieve StateFullness by using Some thing called ViewState
It is implemented as hidden fields in the page to hold data between requests.
This way , asp.net webforms achieves post back mechanism and was able to hold values in bewteen the requests.
Since Http is a stateless protocol , which means it has no relation between requests.
View State is absent in ASP.Net MVC.
So, you have to stop postback by partially posting back . Which means that you need to send an asynchronous request with out refreshing whole page.
It is possible by using AJAX. You can either use
MVC Ajax or Jquery Ajax.
By using AJax, we can eliminate the post back and then do the partial post back.
Solution:
$("#dropdownid").change(function(event e)
{
//Make your ajax request here..
});
Hope this helps
Updated:
$("#dropdownid").change(function () {
$.ajax({
type: "post",
contentType: "application/json;charset=utf-8",
url: /*Your URL*/,
success: function (data) {
//do your callback operation
}
});
});
Got it.
Passing Empid as querystring from jquery like:
<script>
$(document).ready(function () {
$("#ddlemployee").change(function () {
debugger;
var empid = $("#ddlemployee").val();
location.href = '#Url.Action("GetEmployeeDetails", "Employer")?empid=' + empid ;
});
});
</script>
and assign "empid " to model "Empid" in Action method before foreach loop like
model.EMP_ID = empid;//in Controller Action Method before foreachloop of my code
// and this model.EMP_ID binded to dropdownlist.
this EMP_ID passes same id to dropdownlist which was selected. Thats it.
I have a view (Index.cshtml) with a grid (Infragistics JQuery grid) with an imagelink. If a user clicks on this link the following jquery function will be called:
function ConfirmSettingEnddateRemarkToYesterday(remarkID) {
//Some code...
//Call to action.
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
//alert('Succes: ' + remarkID);
//window.location.reload();
//$('#remarksgrid').html(result);
});
}
Commented out you can see an alert for myself and 2 attempts to refresh the view. The location.reload() works, but is basically too much work for the browser. The .html(result) posts the entire index.cshtml + Layout.cshtml double in the remarksgrid div. So that is not correct.
This is the action it calls (SetEnddateRemarkToYesterday):
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
return RedirectToAction("Index");
}
This is the action it redirects to:
[HttpGet]
public ActionResult Index() {
//Some code to retrieve updated remarks.
//Remarks is pseudo for List<Of Remark>
return View(Remarks);
}
If I don't do window.location.reload after the succesfull AJAX post the view will never reload. I'm new to MVC, but i'm sure there's a better way to do this. I'm not understanding something fundamental here. Perhaps a nudge in the right direction? Thank you in advance.
As you requesting AJAX call, you should redirect using its response
Modify your controller to return JSONResult with landing url:
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Controller");
return Json(new { Url = redirectUrl });
}
JS Call:
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
window.location.href = result.Url
});
After Ajax post you need to call to specific Url..
like this..
window.location.href = Url
When using jQuery.post the new page is returned via the .done method
jQuery
jQuery.post("Controller/Action", { d1: "test", d2: "test" })
.done(function (data) {
jQuery('#reload').html(data);
});
HTML
<body id="reload">
For me this works. First, I created id="reload" in my form and then using the solution provided by Colin and using Ajax sent data to controller and refreshed my form.
That looks my controller:
[Authorize(Roles = "User")]
[HttpGet]
public IActionResult Action()
{
var model = _service.Get()...;
return View(model);
}
[Authorize(Roles = "User")]
[HttpPost]
public IActionResult Action(object someData)
{
var model = _service.Get()...;
return View(model);
}
View:
<form id="reload" asp-action="Action" asp-controller="Controller" method="post">
.
.
.
</form>
Javascript function and inside this function I added this block:
$.ajax({
url: "/Controller/Action",
type: 'POST',
data: {
__RequestVerificationToken: token, // if you are using identity User
someData: someData
},
success: function (data) {
console.log("Success")
console.log(data);
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html'); // parse result (type string format HTML)
console.log(htmlDoc);
var form = htmlDoc.getElementById('reload'); // get my form to refresh
console.log(form);
jQuery('#reload').html(form); // refresh form
},
error: function (error) {
console.log("error is " + error);
}
});
I'm wondering if it is possible to achieve the following.
Within an MVC application -
Have a link which queries a database for some values, sets those values as session variables and then opens a pop-up window(which is an asp.net webform within the MVC app)
It's basically to allow us to run Crystal Reports, the link would set the Report ID in a session variable which would then be accessible in the asp.net webform.
My confusion is the setting of the session variable on click of the link and then opening the popup.
Can it be done and if so any links or pointers?
Edit:
Javascript
<script language="javascript" type="text/javascript">
function flagInappropriate(postId) {
var url = "/Home/FlagAsInappropriate/" + postId;
$.post(url, function(data) {
if (data) {
alert("True")
} else {
// callback to show error/permission
}
});
}
Controller
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
[AcceptVerbs("POST")]
public bool FlagAsInappropriate(int id)
{
// check permission
bool allow = true;
// if allow then flag post
if (allow)
{
// flag post
return true;
}
else
{
return false;
}
}
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
}
It can be done, yes. I've achieved something similar for the purposes of generating reports (predominantly so the report URL is hidden from the user and so some tracking and authentication could be achieved using once-off tokens). My solution was as follows:
Perform an AJAX call to a Web Method in your application to set the relevant session variable(s).
Return a value from the Web Method to indicate whether it was successful.
For the "success" event handler of the AJAX call, open your relevant ASPX page to generate the report.
Simple as that. :)
Here's some sample code to attach the click event and do the AJAX call, based on your amended question:
Click to test AJAX call
<script type="text/javascript">
$(document).ready(function () {
$(".flag").click(function () {
flagInappropriate($(this).attr("id").split("-")[1]);
});
});
function flagInappropriate(postId) {
var url = "/Home/FlagAsInappropriate/" + postId;
alert(url);
$.post(url, function (data) {
if (data) {
alert(data);
} else {
// callback to show error/permission
}
});
}
</script>
i have the following javascript that gets HTML from somewhere and sticks it in a textarea for tinymce.
My question is how in asp.net-mvc i can get the HTML Here and stick it in the javascript?
Do i put this in ViewData?
function ajaxLoad() {
var ed = tinyMCE.get('elm1');
// Do you ajax call here, window.setTimeout fakes ajax call
ed.setProgressState(1); // Show progress
window.setTimeout(function() {
ed.setProgressState(0); // Hide progress
ed.setContent('HTML Here');
}, 500);
}
i want to have something like this below, but it doesn't seem to work:
function ajaxLoad() {
var ed = tinyMCE.get('elm1');
// Do you ajax call here, window.setTimeout fakes ajax call
ed.setProgressState(1); // Show progress
window.setTimeout(function() {
ed.setProgressState(0); // Hide progress
ed.setContent(<% ViewData["test"] %>);
}, 500);
}
I think an ajax call might suit you best, but also make sure you're trying <%= ViewData["test"], note the "=" after that first percent symbol. The example you gave won't emit the value of the ViewData field the way you have it there (maybe that was just a typo?).
If you're in an aspx or ascx page then you can do that exactly like in your example - with one minor change :
ed.setContent(<%= ViewData["test"] %>); // the equals sign
If you're in a *.js file then that won't work, but you could set
<input type="hidden" id="myTestData" value='<%=ViewData["test"]%>' />
in the aspx,ascx file and then get the value via jQuery:
$("#myTestData").val();
Edit: damn, I missed the ending %> on the <input line.
I use this;
In my view;
$.post("/jQueryTests/jQueryAddMessageComment", { commentText: commentText }, function(newComment) {
$("#divComments" + id.toString()).html(newComment);
});
Of if I am returning Json data then;
$.post("/Articles/jQueryDownVoteArticle", { id: id }, function(votes) { document.getElementById("ArticleVotes").innerHTML = votes; }, "json");
In my controller;
return PartialView("commentList", new FormViewModel { LastComment = commentText });
The important bit is how you return back to the view. You can also return like this;
return Json(new FormViewModel { LastComment = commentText });
Remember that the control you are replacing the html for needs to have a unique id.
Is this what you asked?