I am trying to set ViewBag.OrderId to the value of the data attribute data-orderId, but I am getting a syntax error on the =:
#foreach (var order in Model.Orders)
{
<a class="btn-add-note" data-orderId="#order.db_OrderNo">Add</a>
}
JS:
$(".btn-add-note").click(function(){
#ViewBag.OrderId = $(this).attr("data-orderId");
});
Anyone know why I am getting this syntax error?
Explanation:
The code shown here is in a partial view. Once clicked, it opens up a modal in it's parent view. The modal has a form in it that requires the selected orderId from the partial view. The orderId is then passed as a parameter into the controller on form submit. I have been having trouble figuring out the best way to do this so I was trying to just set ViewBag.OrderId to the value so I wouldn't have to try to pass it to the form first.
Let me know if that's confusing at all or if more details are needed.
Thanks!
What you are trying to do will not work; #ViewBag.OrderID will have already rendered before that JS code works. You have to evaluate everything on the client, and if you need to access it on the server, store the value in a hidden field or send it to the server using AJAX.
Please provide some more info on what you are trying to do and we can help further.
You can't mix server side and client side code.
What you can do however, is have a hidden field that you store your OrderId in, and then retrieve once you load your modal.
In your view add a hidden field
<input type="hidden" id="orderId" value="" />
Then just set it as you were trying to do with ViewBag
$(".btn-add-note").click(function(){
$('#orderId').val($(this).attr("data-orderId"));
});
Now you can grab the OrderId from the hidden wherever you need it.
If you need the OrderId on the controller to load the form, just add a controller action for setting the ViewBag property
[HttpPost]
public void SetOrderId(string orderId)
{
ViewBag.OrderId = orderId;
}
Then make your click event call this action instead
$(".btn-add-note").click(function(){
$.ajax({
url: '#Url.Action("SetOrderId", "ControllerName")',
type: 'POST',
data: { orderId = $(this).attr("data-orderId") }
});
});
Related
I have a simple Asp.Net MVC app. I have a form, which I'm trying to gather data for, and then submit. However, within that form is a list of selections - each time a selection is made, I go to the server to add that data:
function addSelection(item) {
fetch("/test/selection/" + item,
{
method: "POST"
})
.then(response => {
const name = document.getElementById('Name').value;
localStorage.setItem("name", name);
if (response.ok) {
location.reload();
} else {
console.error("Unable to add");
}
});
}
The server then stores the list in a HttpContext.Session variable.
The target is to keep the name property in place across calls. The code above works great - I set the control on load:
window.onload = function() {
var getName = localStorage.getItem('name');
document.getElementById('Name').setAttribute('value', getName);
}
However, the form itself is eventually submitted, and the entire form, with the selected items, is submitted to the server:
<div>
<input type="submit" value="Submit"
asp-controller="My" asp-action="Create"/>
</div>
The problem that I have is that the local storage still retains the value of name, and so the next time the form is loaded, it's still there. Does anyone have any techniques for achieving the same result without using local storage?
The only solution that I can think of so far is to replace the submit button with a manually coded JS script that resets the value, but that doesn't account for situations where the user just moves away from the form. I feel like I'm heading down a rabbit hole of my own making, and there must be a simpler way to do the same thing.
One solution is to use hidden form fields to persist the data between requests instead of local storage. On each item selection, add the data to a hidden form field on the client-side instead of saving it to local storage. Then, when the form is submitted, the hidden form field value will be included in the form data and can be retrieved on the server-side.
On the server-side, you can retrieve the NameValue from the form data in your action method.
[HttpPost]
public IActionResult Create(string NameValue, ...)
{
...
}
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.
I'm actually running into little problems with my current project. Following case:
I've got a model called "Posting" with relations:
public function subscribers(){
return $this->belongsToMany('User');
}
In my view-file there is a table containing all Postings and also a checkbox for subscribing/unsubscribing with the matching value to the posting-id:
<input class="click" type="checkbox" name="mobileos" value="{{{$posting->id}}}"
#if($posting->subscribers->find(Auth::User()->id))
checked="checked"
#endif
>
Now the thing I want to archive:
A JavaScript is going to watch if the checkbox is checked or not. According to that, the current user subscribes/unsubscribes to the posting. Something like:
$('.click').on('click',function() {
// $posting->find(---$(this).prop('checked')---)->subscribers()->attach(---Auth::user()->id---);
// $posting->find(---$(this).prop('checked')---)->subscribers()->detach(---Auth::user()->id---);
});
Is there any possibility to archieve that or any other ways? I couldn't get my head around this so far.
Cheers,
Chris
If you want to use Ajax to achieve this, you will need a REST endpoint in Laravel for the subscriptions, e.g.:
http://localhost/subscribe/{{userid}}
When this Endpoint is called, the database can be updated. The function could also return a JSON showing, if the saving database in the database successful.
Use this endpoint to make an Ajax Call on click:
var user = {
id: 0 // retrieve the correct ID from wherever it is stored
}
$('.click').on('click',function() {
$.GET('http://localhost/subscribe/' + user.id,
function () { // this is the success callback, that is called, if the Ajax GET did not return any errors
alert('You are subsribed')
});
});
Ideally you won't be using the GET method, but instead use POST and send the user ID as data. Also you would need to retrieve the user ID from session or wherever it is stored.
Take care that as you are using Ajax it can easily be manipulated from the client side. So on the server you should check, if the user ID that was sent is the same as in the Session. Maybe you don't need to send the user id at all, but that depends on how your backend is built.
I am having a hard time deciding on an appropriate way to Perform some server side functionality and then redirecting to the same View in my ASP.Net MVC project.
I am trying to call an Action after the selected index changed client side event of my combobox.
One way I can think of is to change the window.location to the url of my Action and pass the data i need via the query string like this
function SelectedIndexChanged(s,e)
{
window.location.href = "/MyController/MyAction?" + s.GetValue();
}
I also see lots of people saying you should use jquery ajax for this
function SelectedIndexChanged(s,e)
{
$.ajax({
url: 'MyController/MyAction',
data: { value: s.GetValue() },
success: function(){
alert('Added');
}
});
}
My Action looks something like this where i set some cookie values using the value and Set View bags values depending on the selected index.
public ActionResult SelectedIndexChanged(string value)
{
//Do some processing
//Set cookie values
SetViewBags(value);
return Redirect(Request.UrlReferrer.ToString());
}
Is there a better approach to accomplish my task, I am leaning more towards changing the location.href as it is simpler, but i'm not sure if this is good practice?
EDIT
To Clarify this Combobox is a Devexpress MVC extension so I will have to handle the "SelectedIndexChanged" client side event.
This Combobox is also on my layout page so it appears on every view in my project. So when it is changed i will need to to call the same Action no matter what page it is on
As you've indicated that your form is in your layout (not a view), I recommend you look at using a view partial. Fortunately, MVC has already provided an example with their view partial (can't remember the name) that has the login and logout buttons. If a user clicks logout, some javascript is fired and the form is submitted. This will redirect the user; however, you could also send the original address (referrer) as a parameter to your server method and then redirect to that page afterward.
You could always use an Html.Action
function SelectedIndexChanged(s,e)
{
#Html.Action("ActionName", "ControllerName", {optional route values})
}
I am using jQuery serialize() function to collect data in a form and submit to server using jQuery Ajax "post" method, like this: var params = jQuery('#mainContent form').serialize();.
The strange thing I saw is the serialized data from my form contains old data. It means, all of my changes in form (input to text-field, select on combo-box) is not stored to DOM, so when jQuery call serialize(), it collect the old data which appeared before I change the form. I tried to inspect to each element in that form and call .val(), it still showed the old values.
So how can I persist all my changes to form, that the serialize() method can build the string with newest data I entered?
Here is my snippet code, I called serialize() inside submit handler
jQuery('.myFormDiv input.submit').click(function() {
// Do something
// Collect data in form
var params = jQuery('#mainContent form').serialize();
// Submit to server
jQuery.post(url, params, successHandler);
}
Thank you so much.
When are you calling serialize? it should be $('form').submit( [here] ); It sounds like it's being called on page load, before you enter values into the fields, then being used after.
EDIT:
using the submit event instead of on click will catch someone hitting enter in a text field.
jQuery('#mainContent form').submit(function() {
// Collect data in form
var params = jQuery(this).serialize();
// Submit to server
jQuery.post(url, params, successHandler);
}
*the above code assume url is define and successHandler is a function.