jQuery button click + spring mvc navigation - javascript

So my problem in short: I have some html page with a button. When the button is clicked, I would like to move to another page. Looks pretty simple, but I can't figure it out.
So, my button handling logic looks like this:
$("#go").click(function() {
var source = $("#dropdown").text();
$.ajax({
type : "GET",
url : "mainpage.html",
data: {provider: source}
});
})
Now my controller looks like this:
#Controller
public class MainController {
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public ModelAndView hello() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
return mav;
}
#RequestMapping(value = "/mainpage", method = RequestMethod.GET)
public String goToMainPage(#RequestParam("provider") String provider) {
System.out.println("##########################" + provider.trim());
return "empty";
}
}
So the story starts on the page associated with /hello (=index.jsp). The page is found, displayed, everything is all right. However, when I click y button, I can see the bunch of '#' signs printed out, but the page for /hello (index.jsp) is displayed again instead of the one for /mainpage (which should be empty.jsp the file is right there next to the other).
I also tried to return a ModelAndView, but that did not help. I tried to split this controller into two, but it did not help. I tried to use POST instead of GET, you know what happened...
This may be a stupid question, but I'm completely new to Spring MVC.

Ok, finally I figured it out.
I changed my jQuery function to this:
$("#go").click(function() {
var source = $("#dropdown").text();
window.location.href='/mainpage?provider='+source;
});
and controller method to GET.
This also goes through the MVC controller and correctly fetches the value for provider.
Anyways, please let me know if there's a better way to do this.

Related

Getting parameters from query string

I am creating a web page using ASP.Net WebAPi, MVC and Knockout.
I have a normal MVC controller that loads the pages when I need them:
[Authorize]
public class AdminController : Controller
{
public ActionResult Clients()
{
return View();
}
public ActionResult ClientEdit(int? Id)
{
return View();
}
}
And once the page is loaded, my Knockout model takes care of the loading of the data. So, the 'Clients' controller simply loads a list of all clients. When on that screen, a user can click 'Edit' next to a client, and the page is navigated to the 'ClientEdit' controller, which takes an id.
So, my knockout click event looks like this in my knockout view model:
self.EditClick = function () {
if (this.ClientId && typeof this.ClientId !== 'undefined') {
window.location.href = "/Admin/ClientEdit/" + this.ClientId;
}
else
window.location.href = "/Admin/ClientEdit/";
}
(It handles the 'Create New' button and the edit button, hence the 'if')
Once I redirect, the MVC controller loads the page, and the URL is:
http://localhost:49389/Admin/ClientEdit/1
I then load the knockout model, and would like to make an API call to get the data...
After my page loads, I want to bind the view model to the page. Here's my view model at the moment:
function AdminClientEditor() {
var self = this;
self.Name = ko.observable("");
self.ContactName = ko.observable("");
ko.applyBindings(new AdminClientEditor(), $("#clienteditor")[0]);
So, I will create a $.get method that calls a webAPI method that will return me data based on the id. I just need to get the ID somehow.
But, how do I get the Id (In this case, '1', from the URL?
And, is this the right way to achieve what I am trying to do?
You can pass the id value to view via viewbag.
public ActionResult ClientEdit(int? Id)
{
ViewBag.ClientId=id;
return View();
}
and in the view's script section
var clientId="#ViewBag.ClientId";
alert(clientId);
// use this
If your javascript code which accesses this id value is inside a separate external js file, you may set this value to a js variable in your view and access it in your js file. Make sure to use namespacing to avoid global variable overwriting value issues.
So in your view
<script>
var myApp = myApp || {};
myApp.ClientId= "#ViewBag.ClientId";
</script>
<script src="~/Scripts/PageSpecificExternalJsFile.js"></script>
And in the PageSpecificExternalJsFile.js file,
var clientId=myApp.ClientId;
//use this as needed
I'm not sure if this is the best way, but you can get the ID from the URL by using JS:
var id = GetID();
function GetID() {
var href = location.href;
var results = href.split("/");
return results[results.length - 1];
}
I've come up with this solution which works, but I am unsure if it's the best way. It seems pretty good.
I created a MVC ViewModel class in my application code, called 'GenericParameteModel', which at the moment, has a single parameter, "Id".
I then modified my page loading MVC method:
public ActionResult ClientEdit(int? Id)
{
var mv = new GenericParameteModel { Id = Id };
return View(mv);
}
On my View page, I added the model 'GenericParameteModel' to the View.
I created a hidden field, called 'ClientId' on the view.
<input type="hidden" id="clientId" value="#model.Id">
Then, within my knockout view model, I check if $("#clientId").val() has a value. If so, I do the $.get call, using that value, and populate my view model.
In doing so, all my initial page loads from MVC will have the ability to you the GenericParameteModel, and it will be a pattern for other pages. As it's a model, I can add new fields as my application requires.
This seems to work well. I'm unsure if this is an acceptable way as I am new to this (MVC to load views and the Knockout/WebApi to get the data after loading). But it seems neat and manageable.

Custom action result return specific view in MVC C#

I have an MVC application which i am trying to give the user the opportunity to download a zip of files,but unsuccesfully.Let me explain further.
Inside my view(ImageViewer.cshtml) i have a div class with an on click event that when pressed i call the controller method(ImageViewerController.GetZipPhotos) which handles the download of the zip file.See below:
div class="text" onclick="GetZipPhotos()">Download</div>
and the Javascript that get called is this:
function GetZipPhotos() {
$.ajax({
url: '#Url.Action("GetZipPhotos", "ImageViewer",Request.Url.Scheme)',
type: 'POST',
contentType: 'application/zip',
error: function () {
alert('There was an error!'+result);
}
});
}
Now, inside my ImageViewerController i have the following method:
[HttpPost]
public ActionResult GetZipPhotos()
{
ZipResult newZipResult=new ZipResult(
Server.MapPath("~/File1.txt"),
Server.MapPath("~/File2.txt")
);
newZipResult.OutPutZipFileName = "PhotosZip.zip";
return newZipResult;
}
and the declaration of the ZipResult custom action is:
public class ZipResult:ActionResult
{
private IEnumerable<string> _filesToZip;
private string _outPutZipFileName="ZipFile.zip";
public ZipResult(params string[] filesToZip)
{
this._filesToZip = filesToZip;
}
public override void ExecuteResult(ControllerContext context)
{
using (ZipFile oneZipFile = new ZipFile()) {
oneZipFile.AddFiles(_filesToZip);
context.HttpContext.Response.ContentType = "application/zip";
context.HttpContext.Response.AppendHeader("content-disposition", "attachment; filename=" + _outPutZipFileName);
oneZipFile.Save(context.HttpContext.Response.OutputStream);
}
}
}
The problem is that the code ofcourse doesn't work because the name of the view that called the controller is different from the actual method(GetZipPhotos).The view's name is ImageViewer.cshtml and the controller's name is ImageViewerController.
As fas as i have understood, the MVC framework uses code conventions, so it expects the name of the method to be the same as the view.The problem is that my view and the method are diferrent so the response never gets to back to the view.
I thought of creating a new view that has basically nothing inside, just to call it from the method and return the zip file.If this could be a possible solution, how can i tell from the action result which view to send the response?
No need to use ajax for the file download. The browser will normally start the download and keep you on the same page. Also, no need for a custom action result, you can just use FileResult. Try something like this:
public FileResult GetZipPhotos()
{
var filesToZip = new List<string> { Server.MapPath("~/File1.txt"), Server.MapPath("~/File2.txt") };
var oneZipFile = new ZipFile();
oneZipFile.AddFiles(filesToZip);
return File(oneZipFile.ToByteArray(), "application/zip", "PhotosZip.zip");
}
Of course, you'll need to figure out this part oneZipFile.ToByteArray(), but the ZipFile class probably already has something like that.
Your ajax call is redirecting the response into nowhere.
I would do it like this:
use a hidden iframe, change its src to the desired path in your function and it should be prompting a file dialog.

Return View from controller after jquery post

Hi I am new to MVC and I have the below senario
VIEW:
step3.cshtml is my view
This has data binded to step3.js(using knockout)
$.post("/Step/Step4", { "some":some_data }, function (data) {
}, 'JSON');
CONTROLLER:
[HttpPost]
public ActionResult Step4(model foo)
{
//save this data to the database and return a view
using (DBContext dbContext = new DBContext())
{
dbContext.Table.Add(foo);
dbContext.SaveChanges();
}
return View(foo);
}
public ActionResult Step4()
{
//get this view with the model
}
I am able to see that the view Step4.cshtml is able get the property values from model but.
I see that my View Step4.cshtml is a response header from the post how do I render this in the browser.
Is this the right approach??
So is it that an HTML form post can return a view and replace the whole content and AJAX cannot do that except for the partial view update?
When you call $.post, you are making a jQuery ajax request with a POST method. That data is given back to you in the success method. If you are returning the view, then you will have to manually replace the html in your document with that response.
Normally, when you use ajax like this, you would return a PartialView to update a section of your page, not your whole page. You might want to see if you can return a partial and update a div.
You can also do that by using an Ajax.ActionLink, and in the AjaxOptions, specify the id of the element you want to update when the response is returned, and the InsertionMode, which should be set to Replace. And you won't have to worry about replacing the content yourself.
Please see this stackoverflow question, which may help you: How To Use Ajax.ActionLink

call action method with parameters MVC 4 javascript

I'm tired and stupid, but heres my coding problem:
We are using d3.js to draw on a google map element in the MVC4 action method called Live.
We have implemented on click for the d3.js element and need to redirect from the javascript to another MVC action method.
the action method "declaration" looks like this:
public ActionResult Visualization(String appId = "", String userId = "")
In javascript we have inside the d3.js function a code snippet that works and looks like this:
.on("click", function (d, i) {
// just as an example use for the click-event.
alert(d.AppName); }
Where d has AppId, and UserId aswell.
What we now want to do is to create a redirect for the click event, calling the action method along with parameters from d. This means when you click the d3.js element you would be redirected to the other page with pre-set parameters.
We have tried things like:
window.location.href = "/StatsLocationController/Visualization/appId=" + d.AppIdentifier + "/userId=" + d.DeviceId
We also tried to use window.location.replace(), but none of it has worked, I guess we haven't figured out the correct syntax for the actionLink, but have a hard time finding examples when googling it. We are thankful for any help we can get!
Instead of:
window.location.href = Html.ActionLink("Visualization", "StatsLocationController", new{ appId=d.AppId, userId=d.UserId}, new{})
Try:
window.location.href = '#Url.Action("Visualization", "StatsLocationController", new{ appId=d.AppId, userId=d.UserId})'
This is assuming you have your routing set up appropriately?
Edit:
The sort of routing that would make this work is something like:
routes.MapRoute(
"MyRoute",
"{controller}/{action}/{appId}/{userId}",
new {
controller = "Home",
action = "Index",
appId = UrlParameter.Optional,
userId = UrlParameter.Optional
});
Second Edit
I've just noticed that you're calling your controller StatsLocationController - Unless your C# class is called StatsLocationControllerController - this is wrong. Asp.Net MVC assumes that for a controller, there will be a class called StatsLocationController and so you should reference your controllers without the Controller part. So in this example your controller should be called StatsLocation which would make the URL look like this:
#Url.Action("Visualization", "StatsLocation", new{ appId=d.AppId, userId=d.UserId})
I forgot I left this without accepting an answer.
simonlchilds have figured out the problem, that we included the Controller in the call.
So the final call looked like:
window.location.href = "/StatsLocation/Visualization/appId=" + d.AppIdentifier + "/userId=" + d.DeviceId
where StatsLocation is the name of the controller.
Such a silly mistake, but at least it had a simple solution and maybe it can help someone.

URL string parameters passed to MVC controller action arrive as null

Have Controller:
public class MyController : Controller
{
[HttpGet]
public ActionResult MyAction(int iMode, string strSearch)
{
return View();
}
}
In my view I have a div with id=center
I execute the following code in javascript
url = "/MyController/MyAction?iMode=7&strSearch=as";
$('#center').load(url);
When debugger his the breakpoint in my action on first line, iMode variable shows proper value of 7, strSearch parameter arrives as null.
Any help/advice would be most welcome.
Just use the ampersand instead of &
url = "/MyController/MyAction?iMode=7&strSearch=as";
Thanks Innatepirate for the tip. Wasted enough time trying to figure out why controller is getting null values. Replacing & with ampersand did the trick. By the way I was doing the simple age old window.location.href = link and still had the problem. Probably its the MVC parsing and routing that is messing this up.

Categories

Resources