I'm using grail's webflow to manage a multi-stage registration process on my site. A link triggers an event for the start state, and the intention is to load the corresponding view in a fancybox iframe. I used grail's link tag to resolve the URL for the view, but the iframe just displays a '404'.
trigger:
<g:link controller="registration" action="register"
event="enterStandardDetails" class="register" />
The URL resolves to /mysite/registration/register?_eventId=enterStandardDetails.
webflow:
def registerFlow = {
enterStandardDetails = {
on("next") {
// capture mandatory user details
}.to("enterOtherDetails")
}
enterOtherDetails = {
on("next") {
// capture optional user details
}.to("categories")
on("previous").to("enterStandardDetails")
}
registrationComplete = {
// display finished state
}
}
javascript:
$("a.register").fancybox({
'width' : '65%',
'height' : '90%',
'type' : 'iframe'
});
Is it possible to intercept the URL corresponding to the view state before grails renders it? Or, am I over engineering this? Can I just simply pass in the URL of the view corresponding to the start state, whereby the flow is started when the user clicks "next"?
Any ideas, or thoughts would be much appreciated.
Thanks, -Tom
The problem was that I forgot to import fancybox script.
Related
How does one go about displaying a controller action inside of jquery modal dialog?
Firstly you'll need your Javascript to load a url via ajax, this will depend on which kind of modal you are using etc, there's a ton of libraries out there. I will assume you are using the basic JQuery UI dialog Modal.
Example Link
<!-- this points to your action below.. -->
<a class="some-link" title="title here" href="mycontroller/test">testing</a>
Example Javascript (quick example found on google, many examples out there..)
$(document).ready(function() {
$('.some-link').each(function() {
var $link = $(this);
var $dialog = $('<div></div>')
.load($link.attr('href'))
.dialog({
autoOpen: false,
title: $link.attr('title'),
});
});
});
Now you need to make sure your action doesn't render the main layout when providing the content for the modal via the ajax request.
Here's a really simple method of doing that by replacing the base layout with an empty view for ajax requests. This isn't the best method but it's the simplest for this case ;)
Example Action
public function testAction()
{
if($this->getRequest()->isXmlHttpRequest()) {
$this->layout('application/layout/ajax-layout');
}
return new ViewModel(array()); // ..
}
application/layout/ajax-layout.phtml
<?php echo $this->content ?>
I think you want this kind of code http://jqueryui.com/dialog/#modal-message
inside the just display your action
Otherwise it's about to open an url into your modal it's like that http://blog.nemikor.com/2009/04/18/loading-a-page-into-a-dialog/
I have application that redirect user to Index page of some controller from account controller using RedrirectToAction(), after login.
RedirectToAction("Index", "MyController");
It redirects me to //MyApp/MyController/
I also have navigation on MasterPage view, I use ActionLink:
#Html.ActionLink("Index", "SomeOtherController")
... (other links)
That redirects me to //MyApp/SomeOtherController
Problem is in **/** character on the end of the first route. I have partialView on master page that onClick calls jQuery .post().
function SomeFunction(id) {
$.post("Controller/Action", { id: id },
function () {
... some code
});
}
But when I call that function after redirect from login it trys to access this route:
/MyController/Controller/Action
that doesn't extist. If I change my post call to
$.post("../Controller/Action", ...
it works fine, but then doesn't work for nav links becouse they don't have **/** on the end of route.
What should I do? How to get unique paths from RedirectToAction and ActionLink, with or without **/** on the end?
NOTE:
I can use <a></a> for navigation on master page and enter path with **/** on the end, but I would rather use ActionLink
The key here is that you need MVC to generate your routed URLs for you to pass into your jQuery functions.
1.If your jQuery code is nested within your View, the you can do the following:
function SomeFunction(id) {
$.post('#Url.RouteUrl("Action", "Controller")', { id: id },
function () {
... some code
});
}
2.If your jQuery code is located in an external file (such as myScripts.js), then you will need to somehow pass the MVC generated route to your jQuery function. Since this is not tied to an element directly, you probably would be best served to set this as a hidden element in your view.
View
<input type="hidden" id="jsRoute" value="#Url.RouteUrl("Action", "Controller")"/>
JS
function SomeFunction(id) {
$.post('$("#jsRoute").val()', { id: id },
function () {
... some code
});
}
I have question regarding redirection in Grails web-flow.
I am in a view state which will allow users to enter the answers for a question. On 2 wrong attempts I should be able to re-direct the user to view page from different controller. What i mean is
challengeQuestionOne{
onRender() {
//Display question
}
on('next') {BuildQuestion command ->
bindData(flow.recovery,command)
[return the model to flow]
if(command.hasErrors()) {
flow.command = command
return error()
}
if(check for status. If doesnot pass){
flash.message=message(code:'loginForm.account.locked', default: 'Please Contact Admin.')
redirect(controller : "login",action: "login")//how to redirect from here to diff controller
}
if (//compare answer entered) {
}
else{
//set status not active
}
}.to("challengeQuestionTwo")
on(Exception).to("error")
on('cancel').to('finish')
}
I have tried to redirect from onRender . It was redirecting to the page. But how do I display the error msg on the redirected page. How can i forward the error message from one controller to other??
Ivo Houbrechts wrote an excelent tutorial about grails webflow:
Webflow defines its own flash scope. Although it has the same semantics as the standard grails flash scope (the main purpose is to store objects only until after the next request), it is a different scope. This means that objects stored in webflow's flash scope are not visible in standard grails actions.
import org.springframework.web.context.request.RequestContextHolder
....
RequestContextHolder.currentRequestAttributes().flashScope.message = "YourMessage"
You can read more here:
http://livesnippets.cloudfoundry.com/docs/guide/
Flash scope will not work in this case as expected.
Try to use another approach to show error. E.g. you can pass parameters with redirect. Or you can throw some exception and check it on rendered page as follow:
<g:if test="${flowExecutionException}">
<div class="error"><g:message code="loginForm.account.locked"/></div>
</g:if>
I'm using jQuery mobile with PhoneGap, and would like to show a login page the first time the app is used, and show the index page on subsequent loads.
My current solution is to use the following on deviceready
if(!localStorage.registered){
$.mobile.changePage( "#login", { transition: "none"} );
}
However, my issue with this is that you still see the page transition. I would like the login page to be the first page that is visible.
Any advice? Thanks!
This Q is a few months old, it remains unanswered, I don't have any experience with phone gap but I do jQM, so I figured this may help.
I current employ a solution to this on my app by delaying auto initialisation of jQM.
This is an example of how you could based loosely on how my application does it.
(function() {
#stop jQM from auto initialising
$(document).on("mobileinit",function() {
$.mobile.autoInitializePage = false;
});
var my_app = new MyApp();
# custom afterinit event is triggered on the app instance
$(my_app).on('afterinit',function() {
var initial = 'login';
if(localStorage.registered) {
initial = 'home';
}
# set the page hash to our start page
window.location.hash = initial;
#initialise jQM
$.mobile.initializePage();
});
})();
Make sure you secure the thing that decides if login is allowed, in my application I have a data structure that is required by the app ajax in to MyApp.appdata it will only be there if login was actually successful.
Another solution may be to have a proxy page.
A different approach that I employed on another app.
An initial "loading" step, which is just a dummy page.
Make a page in your doc as the first page, eg.
<div id="loading" data-role="page">Loading</div>
in the mobileinit step bind to the pageshow event.
$(document).on("mobileinit",function() {
$('#loading').on('pageshow',function() {
# ...
# do login check here
# ...
var initial = 'login';
if(localStorage.registered) {
initial = 'home';
}
# change to our initial page
$.mobile.changePage(initial);
});
});
What about hiding #registration and #login then do:
if(localStorage.registered){
$('#login').show();
} else {
$('#registration').show();
}
I have forms located in multiple areas in my layout page (not nested).
I have a partial view which performs a post to controller action.
What action result do I return in that post to keep the user on the current page?
Is jquery/ajax my only option? I would rather a solution that didn't depend on javascript, maybe even a solution that degrades nicely.
You can use the Request.Referrer property to see what page the user has come from and then just use that to redirect them back there.
This does introduce other issues, e.g. losing ModelState, so you'll have to design for that. Also note that some users can block sending referrer information in their requests to the server - so the Referrer property can be null.
I would recommend using AJAX and then falling back on this.
You just need to do a RedirectToAction("") back to your main view.
To post a form without submitting the whole page, which refreshes the browser, you need to use Ajax/jQuery. The degraded solution is to submit the whole page like you would with a normal form.
Here's how I do it with jQuery.
Html:
<div id="RequestButtonDiv">
<button id="RequestButton" name="Request" type="button">Request</button>
</div>
This calls AddToCart on my Request controller when the RequestButton button is clicked. The response is placed inside the RequestButtonDiv element.
<script type="text/javascript">
$(document).ready(function () {
$('#RequestButton').click(function (event) {
$('#RequestButton').text('Processing...');
$('#RequestButton').attr('disabled', true);
submitRequest();
});
});
function submitRequest() {
$.ajax({
url: '<%: Url.Action("AddToCart", "Request", new { id = Model.RowId, randomId = new Random().Next(1, 999999) } ) %>',
success: function (response) {
// update status element
$('#RequestButtonDiv').html(response);
}
});
}
</script>
Controller action:
public ActionResult AddToCart(int id)
{
var user = AccountController.GetUserFromSession();
user.RequestCart.AddAsset(id);
return View("~/Views/Assets/Details_AddToCart.ascx");
}
The controller returns a partial view. You could also return Content("some stuff") instead.
Holler if you have questions or need more detail.