Django Crispy Forms - Add Button via Helper - django

I studied the Crispy-Forms documentation and I tried to put an extra button into one of my forms. With
self.helper.add_input(Button('back', "Back", css_class='btn'))
I can add a nice button. But the Button() wont take an onclick or on_click-attribute. So how can I add logic to this button? Adding an onclick event with JQuery isnt a very nice solution...
Thanks!
Ron

Are you certain that Button will not take onclick in its kwargs?
I just added an onclick="javascript here" to a Submit() element and it displayed fine.
I also peered a bit at the underlying code, and I think all inputs by default flatten the kwargs that aren't popped because of special use (i.e. template), and pass those through into the rendered HTML. This may be new since April '12 (when originally posted), but it currently seems to be as simple as the following:
self.helper.add_input(Button('back', "Back", css_class='btn', onclick="alert('Neat!');"))

This is not included by default (afaik..).
If you just need this once, is possible to use crispy-forms HTML Layout Object
HTML('<input type="button" name="Save" onclick="do_whatever" />')
What do you then dislike using jQuery? You could handle this rather easy and generic, using something like:
$('form :submit.ajax_submit').live('click', function(e) {
e.preventDefault();
var my_form = $(this).parents('form');
// do whatever
alert(my_form.attr('id'));
alert(my_form.attr('action'));
});
and then just pass the class:
Submit('save', 'save', css_class='ajax_submit')

Related

CFWheels: Display form errors on redirectto instead of renderpage

I have a form which I am validating using CFWheels model validation and form helpers.
My code for index() Action/View in controller:
public function index()
{
title = "Home";
forms = model("forms");
allforms = model("forms").findAll(order="id ASC");
}
#startFormTag(controller="form", action="init_form")#
<select class="form-control">
<option value="">Please select Form</option>
<cfloop query="allforms">
<option value="#allforms.id#">#allforms.name#</option>
</cfloop>
</select>
<input type="text" name="forms[name]" value="#forms.name#">
#errorMessageOn(objectName="forms", property="name")#
<button type="submit">Submit</button>
#endFormTag()#
This form is submitted to init_form() action and the code is :
public function init_form()
{
title = "Home";
forms = get_forms(params.forms);
if(isPost())
{
if(forms.hasErrors())
{
// don't want to retype allforms here ! but index page needs it
allforms = model(tables.forms).findAll(order="id ASC");
renderPage(action="index");
//redirectTo(action="index");
}
}
}
As you can see from the above code I am validating the value of form field and if any errors it is send to the original index page. My problem is that since I am rendering page, I also have to retype the other variables that page need such as "allforms" in this case for the drop down.
Is there a way not to type such variables? And if instead of renderPage() I use redirectTo(), then the errors don't show? Why is that?
Just to be clear, I want to send/redirect the page to original form and display error messages but I don't want to type other variables that are required to render that page? Is there are way.
Please let me know if you need more clarification.
This may seem a little off topic, but my guess is that this is an issue with the form being rendered using one controller (new) and processed using another (create) or in the case of updating, render using edit handle form using update.
I would argue, IMHO, etc... that the way that cfWheels routes are done leaves some room for improvement. You see in many of the various framework's routing components you can designate a different controller function for POST than your would use for GET. With cfWheels, all calls are handled based on the url, so a GET and a POST would be handled by the same controller if you use the same url (like when a form action is left blank).
This is the interaction as cfwheels does it:
While it is possible to change the way it does it, the documentation and tutorials you'll find seem to prefer this way of doing it.
TL; DR;
The workaround that is available, is to have the form be render (GET:new,edit) and processing (POST:create,update) handled by the same controller function (route). Within the function...
check if the user submitted using POST
if it is POST, run a private function (i.e. handle_create()) that handles the form
within the handle_create() function you can set up all your error checking and create the errors
if the function has no errors, create (or update) the model and optionally redirect to a success page
otherwise return an object/array of errors
make the result error object/array available to view
handle the form creation
In the view, if the errors are present, show them in the form or up top somewhere. Make sure that the form action either points to self or is empty. Giving the submit button a name and value can also help in determining whether a form was submitted.
This "pattern" works pretty well without sessions.
Otherwise you can use the Flash, as that is what it was created for, but you do need to have Sessions working. their use is described here: http://docs.cfwheels.org/docs/using-the-flash and here:http://docs.cfwheels.org/v1.4/docs/flashmessages
but it really is as easy as adding this to your controller
flashInsert(error="This is an error message.");
and this to your view
<cfif flashKeyExists("error")>
<p class="errorMessage">
#flash("error")#
</p>
</cfif>

Setting selected entry using helper.options?

Im am using Play 2.0.4 and
helper.options(myitems)
in my template (inside of a helper.select)
In this case, how can I define the default selected entry, which shall be one entry out of myitems? Thanks for any hint!
A little bit more about my case:
Imagine a news archive, showing all news titles. This news archive uses pagination, pagination uses GET to pass the next/previous page number.
The play framework however will only correctly select the currently selected "select" item (here: news category) when a POST request was used - while pagination uses GET!
Intended behaviour: While a filter is applied / a specific news category is selected, this shall always be visible to the user by preselecting the currently selected news category in the "select" form.
A "screenshot" for illustration:
So, anyone having a good idea on how to cope with this problem? Any way to tell Play manually which entry from the "select" form it shall select? '_default always adds a new entry instead of selecting one out of the given options ): Would be great, if one wouldn't have to build the complete "select" form manually.
Try passing '_default option to select helper:
#import views.html.helper._
#select(form("email"), options(List("first", "third")), '_default -> "second")
It seems, unfortunately, the only way to figure it out is to look up the source.
Update:
Specifying _default property doesn't set selected attribute on option tag. It looks like the only way to preselect entry is to pass prefilled form to the template. For example, suppose you have following form:
case class RegInfo(email: String, color: String)
private val registrationForm = Form(
mapping(
"email" → email,
"color" → nonEmptyText(minLength = 5, maxLength = 32)
)(RegInfo.apply)(RegInfo.unapply)
)
Then in the action prefill form before passing to the view:
def create = Action {
Ok(html.create(registrationForm.fill(RegInfo("user#qwe.com", "blue"))))
}
Then in template use helper:
#select(form("color"), options(List("red", "green", "blue")))
And value will be preselected.
Ended up with the pragmatic approach:
<select id="myfield" name="myfield" >
<option class="blank" value="">-- All items --</option>
#for((key, value) <- MyModel.options) {
#if(key == GETValuePassedToTemplate) {
<option value="#key" selected>#value</option>
} else {
<option value="#key">#value</option>
}
}
</select>
Still wondering if there is a better option / way to do it.
Actually, there is a nicer solution to it. If you call the template having the form partially bound you will achieve your goal. Here's the code for your controller:
Ok(views.html.myForm(myForm.bind(
Map("fieldName1" -> "value1",
"fieldName2" -> "value2"))))
Make sure you map fieldnames to the values of the options you want pre-selected.
Still wondering if there is a better option / way to do it.
Well, if your not hell-bent on using play to solve this particular problem, you could always solve it using JavaScript and jQuery:
$(function () {
$('#yourSelect_id').val(5);
}
Where your select options each has values and the one option you whish to pre select has value 5.

JQuery - DatePicker not working in popup forms

DatePicker is not working in a popup form, what could I've done wrong?
The form is in a .php format and is triggered by this javascript function below:
function popitup_request(url, ar){
var f = document.forms[0];
if(ar==""){
alert("Please choose at least one record.");
return false;
}
newwindow=window.open(url, 'name', 'toolbar=0,location=0,directories=0,status=1,menubar=0,scrollbars=1,resizable=0,
width=570,height=280');
if (window.focus) {
newwindow.focus()
}
newwindow.moveTo(screen.availWidth/2-(500/2),screen.availHeight/2-(300/2));
}
the form loads but when you click on the icon-trigger nothing happens.
I already tested including the jquery-1.7.1.js on both main.php and popup.php.
I assume you bind the Datepicker widget to the form elements in your main view. Since popup is loaded later (on popitup_request), the date fields on that form will not be bound to datepicker.
Include the datepicker js and css only once, in your main view. Add a small javascript to the bottom of your popup form, something along the lines of
<script type="text/javascript">
$("input.date").datepicker();
</script>
Btw, your code does not reflect best practices in a number of ways (pixel based layout, magic numbers, mixing native Javascript and jQuery though it's not needed). I'd suggest you go through both a Javascript and a jQuery tutorial to see suggested patterns and good examples for enhancing web pages with Javascript.

Django Flowplayer overlay does not submit form

I am trying to use flowplayer's overlay to load an external page that has a django form built in.
However the overlay loads the page but the submit button simply refreshes the page.
How do i actually submit the values entered in the form?
<script src="http://cdn.jquerytools.org/1.2.5/full/jquery.tools.min.js"></script>
<script>
$(function() {
// if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: {
color: '#ebecff',
loadSpeed: 200,
opacity: 0.9
},
effect: 'apple',
closeOnClick: false,
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
}
});
});
</script>
<div class="bananas">launch</div>
my view boom has a model form.
Without seeing the actual view code, it's hard to give a helpful answer. In the future, please be sure to do so...
If you don't have the overlay programmed to redirect to the page, then submitting it to that same url might process/save the data without you noticing. Is the data being saved, or does absolutely nothing happen when you click 'submit'?
Generally, this is how it works: you need to be posting to a url, defined in urls.py, that points to a view function in your views.py. (These names are merely convention, and can be called whatever you like) You mentioned that you have a view named 'boom': is it defined in your urls.py like this?
url(r'^path/to/boom/$', 'model.views.boom',),
Check that this is defined and that your form is posting to it.
The view must then contain logic to process the request and return a response. Posting to that url will transfer a cleaned_data dictionary of form variables that can be accessed over the field names defined in the form. It looks like this: x = form.cleaned_data[x]. Check the form for its validity with form.is_valid(), and then do your processing. This can involve saving objects, running arbitrary code, whatever you wish.
To find out more, be sure to read the excellent documentation.

Adding an extra button to one object in django admin

I hope this hasn't been asked and I just missed it, but I searched a bunch and couldn't find anything.
I'm adding an extra save button to the django admin when adding or changing an object. Doing that is fairly easy. I just overrode the submit_line.html to add the extra button and then overrode the save_model function to check for the name of that button. It works great.
My problem is that I only need this button to appear for one particular object... not all of them. I looked in change_form.html to see how it knows what object it is dealing with and found {{ opts.module_name }}, but it doesn't seem to be accessible in submit_line.html. I tried printing it out and nothing showed up.
I also thought about hacking save_as (not very graceful, but I don't really care for this particular project), but that button only shows up on change.. not on add, so that won't work.
Does anyone know how to detect what object I'm working with in submit_line.html? Or any other way of doing this?
Thanks!
You can do it using javascript like this:
/static/js/useful.js
$(document).ready(function ($) {
$('input[name="_addanother"]').before('<input type="submit" name="_use" value="Useful functionality"/>');
});
and in your ModelAdmin add:
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('/static/js/useful.js',)
You should be able to access the original object in change_view's context through original. For example {{ original.id }} should print its id!