I have a .NET web app that simply works in this way: Page A where I send an input (barcode scan result) and then it goes to Page B to load a table created by many queries and inserted results in a view model.
What I want to do is that when I go to scan another barcode while I am in Page B, it has to do the same operation that it does with Page A: Page B with new results. It means that through AJAX I send a parameter to the controller, it makes his queries and operations and then it has to return a View with the new View Model and reload the page. Problem it is that it doesn't reload the page with new View Model, but it stays with the old data.
I also tried putting the table in a partial view and try to make it reload after every input in Page B, but it doesn't load all the javascript code in the page which is the most important thing I need to keep (editing table values etc..). Javascript code is contained in Page B, not in partial view ".cshtml".
AJAX CODE: I send an ID to the controller, and it returns an HTML which I put on the ID of a div containing the partial view of the table.
$.ajax
({
type: 'POST',
url: '#Url.Action("QueryBollaTestP", "Bolla")',
data: JSON.stringify({ 'NumBolla': evt.state.code }),
contentType: 'application/json; charset=UTF-8',
dataType: "html",
success: function (data)
{
$(".tesst").html(data);
},
})
Controller:
[HttpPost]
public ActionResult QueryBollaTestP(string NumBolla){
......... all operations and queries..... going to pickingViewModel for the table
return PartialView("_BollaTable", pickingViewModel);
}
Is there anything for that? Doesn't matter if it is with the use of partial view or not, important is it will update the model of the page with the correct data and then it loads the javascript code.
Is the only variable the bar code (NumBolla?)? What is the purpose of Page A?
I would think you only need a single View.
public async Task<ActionResult> PageA(int NumBolla){
..do stuff create model
return View(model)
}
to load a new bar code scan via js: window.location.href = "../PageA/" + NumBolla;
Related
I have a screen that has two partial views
A Partial view container a controller that lets the user select options to filter
A Partial view containing a list of data rows
I can successfully pass the selected options from to the controller via ajax which then returns a partial view to replace the html of partial view 2, but it loses all of the rows as it has no context of the original view model data.
I have tried putting the view model into a hidden field on the index view and passing the relevant child object as json via ajax, but it blows out the JSON max length.
"The length of the string exceeds the value set on the maxJsonLength property."
ViewModel
[JsonIgnore]
public string MyListJson
{
get { return JsonConvert.SerializeObject(MyList); }
}
Index.vbhtml
#Code Html.RenderPartial("_Selection", Model) End Code
<div id="TargetDiv">
#Code Html.RenderPartial("_DataList", Model.MyList) End Code
</div>
#Html.Hidden("hdnViewModelJson", Model.MyList))
javascript.js
$.ajax({
type: "POST",
url: 'Main/UpdateRows',
contentType: 'application/json',
data: { testList : $('#hdnViewModelJson').val() },
success: function (data) {
alert("success")
$("#TargetDiv").html(data)
}
});
MainController
Public Function UpdateRows(testList as MyListType)
//Maniupulate rows based on parameters
Return PartialView("_ListSchemeBoardType",testList )
End Function
Is there a better way to update part of Partial View 2s view model without having to reprovide it?
How do I get the data from the view model into the controller if not?
The best way to refilter a table in jQuery is described here.
Within my dashboard page in my application I want to display a map legend that populates dynamically depending on the values given to the HTML that displays this legend.
This is what the legend should look like:
I am populating this legend using javascript; My JavaSCript function returns an array of nested hashes that would look something like this:
[
{title: 'Downtown Loft', color:'#ade8ad'},
{title: 'Midtown Mansion', color:'#bd95ff'}
]
The Problem
In order to accomplish this, I need to be able to send the array above from my pages.js.erb file to my pages_controller.rb file, specifically to the dashboard action. Within this controller method, I will assign the data from my JavaScript to an instance variable called #calendar_legend
To verify this works, I will call <%= #calendar_legend %> in my dashboard.html.erb view and expect for it to show the array... unfortunately this does not work.
I've tried render json: #calendar_legend in my controller and I always get a null value when viewing that page.
Here's how I've tried sending the data to my controller:
function calendarLegend(){
const legendarray = [
{title: 'Downtown Loft', color:'#ade8ad'},
{title: 'Midtown Mansion', color:'#bd95ff'}
]
$.ajax({
type:'POST',
url: 'pages/dashboard',
data: JSON.stringify(legendarray),
contentType: 'application/json'
});
};
$(document).ready(function(){
calendarLegend();
});
and here's how I've tried assigning it in my controller
def dashboard
#calendar_legend = params[:legendarray]
render json: #calendar_legend
end
and in my view
<%= #calendar_legend %>
This hasn't worked, among with any other solution that I found on Stackoverflow and various other sites.
The issue is that you are rendering the variable #calendar_legend that has not yet been set. Also the Ajax function does nothing to render the result on the page after it has been called.
I'm not exactly sure what you are trying to accomplish here, but here are some suggestions.
First, you could just set the #calendar_legend variable in the controller action that loads the dashboard.html.erb page (instead of calling another action once the page has loaded using Ajax). If you do this, you could just remove the Ajax function altogether.
Second, if you are set on trying to load data to change the legend after the page has loaded, you need to handle the response from the server. There are 2 ways I can think of to easily do this:
Add a response handler into the AJAX method (example from the jQuery Ajax docs - https://api.jquery.com/jquery.ajax/) - in this example, the 'data' variable in the .done function would contain the value of #calendar_legend that you are rendering as json from the controller action, so you need to add it to the page:
$.ajax({
type: 'POST',
url: "pages/dashboard",
data: JSON.stringify(legendarray),
contentType: 'application/json'
}).done(function(data) {
$('.div-with-calendar-legend-data-inside').html( data );
});
You could also do this with Rails using a js.erb template with the same name as your controller action (instead of adding the response handler to your Ajax function). First you would modify your controller action to just set the variable and not render anything (and instead let Rails render the js.erb template):
def dashboard
#calendar_legend = params[:legendarray]
end
Then create the template app/views/pages/dashboard.js.erb, and add something like this to it:
$('.div-with-calendar-legend-data-inside').html( <%= #calendar_legend %> );
Both of these options would require that you add a div (with a class or ID) in your view to add the #calendar_legend data into:
<div class="div-with-calendar-legend-data-inside">
<%= #calendar_legend %>
</div>
Typically, I would only try to load data with Ajax if you are trying to reload the legend when the user makes a change on the page (ie. they select something from a dropdown or some other form input) - then you can send the data with Ajax to the controller and let it update the legend without refreshing the page. However, when doing that I would just use a form_tag and set remote: true on it, then use jquery to submit the form when the inputs change and handle the response with the js.erb template - I think this is cleaner than using the Ajax function.
Hopefully this helps
This is an MVC 5 project. I am having a problem getting a second view to be shown from a parent view. My parent view is a purchase order which has line items. The line items are to be added by launching a second view from the parent view. Both views use the same controller but each has their own action method.
I use the below JavaScript from the PurchaseOrder view to pass data to PurchaseOrderAddItem view (child view):
$(document).ready(function () {
$('#PurchaseOrderLineItemAddId').click(function () {
var aPurchaseOrderViewModel = #Html.Raw(Json.Encode(Model));
var selectedVendorText = $('#ddlvendors option:selected').text();
var selectedVendorValue = $('#ddlvendors option:selected').val();
var LineItemReqJsonObj = {};
LineItemReqJsonObj.PurchaseOrderId = aPurchaseOrderViewModel.PurchaseOrderId;
LineItemReqJsonObj.VendorText = selectedVendorText;
LineItemReqJsonObj.VendorValue = selectedVendorValue;
var dataToPass = '{aLineItemReqJsonObj: ' + JSON.stringify(LineItemReqJsonObj) + '}';
$.ajax(
{
type: "POST",
//data: '{ aPurchaseOrderViewModel: ' + JSON.stringify(aPurchaseOrderViewModel) + ' }',
//data: aPurchaseOrderViewModelStr,
data: dataToPass,
url: '#Url.Action("PurchaseOrderAddItem")',
contentType: "application/json; charset=utf-8",
datatype: "json"
})
.done(function (aNewLineItemViewModel) {
AddNewLineItemReceived(aNewLineItemViewModel);
})
.fail(function (xhr) {
alert('error', xhr);
});
});
});
Below is the action method in the controller which receives the above ajax request:
[HttpPost]
public ActionResult PurchaseOrderAddItem(LineItemReqJsonObj aLineItemReqJsonObj)
{
LineItemViewModel aLineItemViewModel = new LineItemViewModel();
aLineItemViewModel.PurchaseOrderId = aLineItemReqJsonObj.PurchaseOrderId;
aLineItemViewModel.VendorId = Convert.ToInt32(aLineItemReqJsonObj.VendorValue);
return View(aLineItemViewModel);
}
Below is the class in the controller which gets data filled into it as it is passed in from the JavaScript:
public class LineItemJsonObj
{
public string PurchaseOrderId {get;set;}
public string VendorText { get; set; }
public string VendorValue { get; set; }
};
The below diagram illustrates what I am trying to do:
As the diagram shows, I am unable to get the PurchaseOrderAddItem View to be shown. How do I get the PurchaseOrderAddItem View to show, receiving parameter data, after the PurchaseOrder View has invoked the PurchaseOrderAddItem Action From the controller?
Thanks in advance.
-- UPDATE 2/17/2020 1:38PST--
I am probably incorrect in thinking the controller could start the PurchaseOrderAddItem View which when
closed could get the resulting new model data somehow back to the PurchaseOrder
View with the JavaScript that started this.
I am beginning to think this approach using the JavaScript $Ajax to
reach the controller is not the right way to do this. I'm checking now to see
if maybe I should of just loaded another web page from the PurcahseOrder View
with parameter data to create a new PurchaseOrderAddItem View. The challenge here though would
be to probably pack up the entire PurchaseOrder view model data to go with the
PurchaseOrderAddItem View request. If I have the entire PurchaseOrder View Model
data when I exit the PurchaseOrderAddItem View I will be able to load a new
PurchaseOrder View and pass it all the data that was in the first instance so it
is repopulated to include the newly added line items. I'm not sure this is
the right way to do this. I have not seen any examples yet of how this type of
application view presentation problem is handled. I would appreciate it if anyone can
point me to any internet articles that perhaps cover how to design this type of
MVC application. This is very easy to do in desktop apps but web development
with MVC makes this very different and needing a lot more work than something
in WPF or WinForms.
The solution for me in this case was to use the TempData dictionary object to help transport data from the PurchaseOrder View request to the LineItem View and back. There is no sensitive data in this data transport so using TempData should be fine. Additionally, to launch the LineItem view to create a new Line Item worked better for me to just us the standard submit action from within an Html.BeginForm block. The standard post operation provided by the submit button is what I used in this case rather than a button to run $.Ajax code in a JavaScript. Ajax was really not needed in this case since the whole PurchaseOrder View was to be replaced by the LineItem create view.
As a followup to my earlier question about using Thymeleaf and preventing page refresh:
http://forum.thymeleaf.org/Preventing-page-refresh-Thymeleaf-amp-Spring-MVC-td4029155.html
Basically I had a working Spring MVC app that uses Thymeleaf to save form data. When the user saves the data the page would refresh (since I wanted to leave them on the page for more edits) and I wanted to eliminate the page refresh.
I have coded up some Javascript to use JQuery Ajax to post the data to my Spring MVC Controller. The trick seemed to be to not use a submit button, just a regular button and bind a JS function to it for sending the data to the server.
It all seems to work perfectly, but I want to make sure I understand what is happening. In particular I'm wondering if Thymeleaf is now redundant. I don't think it is because when I initially load the page Thymeleaf is still bound to the data bean. From using the debugger on the server side in the controller it looks like the post request calls the mapped method and passes in the data to the model.
I would appreciate your comments on whether or not this is the correct way to accomplish this.
Finally, how do I handle an error, say for example the repository fails to persist the data for any reason?
Thanks very much.
Here are the important parts of the form:
<FORM id="adminDataForm" action="#" th:action="#{/admin_ajax}" th:object="${adminFormAjax}" method="post">
<input type="button" value="Save Changes" id="post" onClick="sendData()" />
Here is the Javascript:
function sendData()
{
$.ajax(
{
type: "POST",
data: $("#adminDataForm").serialize(),
cache: false,
url: "/admin_ajax",
success: function(data)
{
alert("Your changes have been saved");
},
error: function()
{
alert("Error - Data not saved");
}
});
}
Here is the controller:
#SessionAttributes("adminFormAjax")
#Controller
public class TestController
{
final static protected long INDEX_RA = 2L;
#Autowired
private AdminDataRepository rep;
#RequestMapping(value="/admin_ajax", method=RequestMethod.GET)
public String adminFormAjax(Model model)
{
AdminData ad = rep.findById(INDEX_RA);
// If there is no configuration record, create one and assign the primary key
if(ad == null)
{
ad = new AdminData();
ad.setId(INDEX_RA);
}
model.addAttribute("adminFormAjax", ad);
return "adminFormAjax";
}
#RequestMapping(value="/admin_ajax", method=RequestMethod.POST)
public #ResponseBody AdminData adminSubmit(#ModelAttribute("adminFormAjax") AdminData ad, Model model)
{
rep.save(ad);
model.addAttribute("adminFormAjax", ad);
return ad;
}
}
So breakdown of answer.
Thymeleaf not redundant, it will still render the HTML page prior to sending to client. Ajax just does the further processing for you on client side.
You can use submit button as well, you just need to ensure your form is properly structured and you have javascript listening for your submit button click e.g.
$("#submitbutton").on('click', function (){//do stuff});
You handle any and all exceptions/issues within your Ajax controller as you would with standard controller. You need to separate issue handling at different levels. e.g. respository level issues should be managed at rep level, controller/pojo should be at controller level (or pojo if you using one for processing). You should also be capturing any exceptions through a global medium (e.g. ControllerAdvice).
Any issues/errors you pick up you should be communicating back via your return call in adminSubmit, and managing the relevant client response in ajax.
Scenario:
I have written an MVC wizard that automatically uses ajax if javascript is enabled in the browser. Each step of the wizard is a PartialView (I'm using ASP.NET MVC 3).
All works fine.
The problem is refreshing the page if, for example, the user's status changes as a result of how she fills in the wizard. EG, if the wizard logs the user in, or registers them. As the wizard 'moves' from step to step by getting Partial Views via AJAX, the page doesn't get refreshed to reflect the change in the user's status (eg, an anonymous user is now registered).
What I want to do:
Essentially, when I need a full page refresh, I need to AUTOMATICALLY run the following on the client AFTER delivering the Partial View corresponding to the current step of the wizard via AJAX:
location.reload();
The Problem:
As the DOM has been modified via AJAX, I don't know how to make my javascript (location.reload();) run WITHOUT user intervention (eg, clicking a button).
Any suggestions? I have been off work for a while and am struggling to get back up to speed.
For now, I have solved my problem using the code in the following article:
Redirecting after AJAX call, when using ASP.NET MVC
I like the approach discussed in the article because it results in reusable code, in a very MVC way - I already have a base controller (AjaxController.cs) where I encapsulate all my AJAX aware code and this is a nice addition to it.
However, there are two issues with this approach:
I have to redirect away from my wizard, so it only works for the final step of the wizard. If the user's status changes half way through the wizard, I am still jiggered.
I would still like to know how to refresh my page after an AJAX call, rather than just redirecting like this.
So if anyone has the answer, I will gladly give them the biscuit.
I am not quite sure how your ajax calls are structured, but if you are using the MVC Ajax helper you can just call location.reload(); in the OnComplete method, like so:
#using (Ajax.BeginForm(new AjaxOptions{OnComplete = "javascriptfunction"}))
{
//Data and submit button
}
<script>
function javascriptfunction(){
location.reload();
}
</script>
// C# code
public ActionResult Foo(Bar bar)
{
// code here
return Json(new
{
Success = true,
Value = this.RenderPartialViewToString("PartialViewName", bar),
Callback = "window.location.href = 'http://yourdomainurl.com/';"
});
}
// jQuery Ajax
$.ajax({
type: "POST",
url: "/urlWhereToPost",
data: ("form#id").serialize(),
dataType: 'json',
async: false,
beforeSend: function() {
// some instruction
},
error: function(e) {
alert(e.responseText);
},
success: function(data) {
if (data.Success) {
if (data.Callback != null) {
if (data.Callback.length > 0) {
jQuery.globalEval(data.Callback);
}
}
}
else {
// do something
}
}
});