Template/Form Errors and DynaTree.js

79 views
Skip to first unread message

Timothy W. Cook

unread,
Feb 27, 2014, 6:38:25 AM2/27/14
to django...@googlegroups.com
I have no idea where to start on this problem. 
My application is work great using the admin UI but to enhance usability it is time for a new user interface.  

I am using dynatree.js to create a 'Project' tree with subelements (called PcTs) grouped into types;  IOW:  There are three levels before you get to an editable component.  Hence the reason to use a tree instead of paging through the admin UI.  

So my  UI (Selection_001.png)  uses <div> tags to layout the spaces.  Basically tree on the left and a larger editing space next to it.  My forms a re properly placed inside the scrollable <div>.  My problem is when I get an error in the form, how do I control it so that it is only displayed in the same <div> where the form was displayed?  What I get now is a full page reload. See Selection_002.png

The template does not use any extend or include directives.  It is a completely self contained HTML file.
There are forms and views for each of the PcTs. 


Any ideas on where to start working on this?  





--
MLHIM VIP Signup: http://goo.gl/22B0U
============================================
Timothy Cook, MSc           +55 21 994711995
MLHIM http://www.mlhim.org
Like Us on FB: https://www.facebook.com/mlhim2
Circle us on G+: http://goo.gl/44EV5
Google Scholar: http://goo.gl/MMZ1o
LinkedIn Profile:http://www.linkedin.com/in/timothywaynecook
Selection_001.png
Selection_002.png

Andreas Kuhne

unread,
Feb 27, 2014, 7:42:17 AM2/27/14
to django...@googlegroups.com
Hi Timothy,

What you probably have to do is submit the form in a ajax call via jquery for example. https://api.jquery.com/jQuery.ajax/

You create a request via the ajax method in jquery and then add a success and error handler. They only have to update the div you want to replace: $("#div_id").html(response).

That way you will be able to acheive what you are looking for.

Regards,

Andréas

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CA%2B%3DOU3UZppis4c8rr_Ok9rQ_SO6uXK6iii8HG7cPHE9qq1CWLw%40mail.gmail.com.
For more options, visit https://groups.google.com/groups/opt_out.

Timothy W. Cook

unread,
Feb 27, 2014, 8:06:10 AM2/27/14
to django...@googlegroups.com
Hi Andreas,

Thanks for the reply.


On Thu, Feb 27, 2014 at 9:42 AM, Andreas Kuhne <andrea...@suitopia.com> wrote:
Hi Timothy,

What you probably have to do is submit the form in a ajax call via jquery for example. https://api.jquery.com/jQuery.ajax/

You create a request via the ajax method in jquery and then add a success and error handler. They only have to update the div you want to replace: $("#div_id").html(response).



This certainly seems like a reasonable approach.  The points I am unsure of is:

1)  how do I catch the template error in jQuery?

2) I suppose that I have to (somehow) catch the error in the ModelForm? 

3) then send that request to jQuery, somehow?  

My forms and views are pretty simple at this point.  Here are examples:

class DvCodedStringCreateView(CreateView):
    template_name = 'dvcodedstring_create.html'
    success_url = '/dashboard'
    model = DvCodedString
    form_class = DvCodedStringCreateForm
    fields = ['published','prj_name','data_name','lang','description','sem_attr','resource_uri','asserts',
                'terminology','term_subset','codes','t_code','t_string','t_name','t_abbrev','t_version',
                'min_length','max_length','exact_length','enums','enums_annotations','default_value',]




class DvCodedStringCreateForm(forms.ModelForm):
    class Meta:
        model = DvCodedString
        widgets = {
                    'data_name': TextInput(attrs={'size':90}),
                    'description': Textarea(attrs={'cols':80, 'rows':5,'wrap':'off'}),
                    'sem_attr': Textarea(attrs={'cols':15, 'rows':3,'wrap':'off'}),
                    'resource_uri': Textarea(attrs={'cols':60, 'rows':3,'wrap':'off'}),
                    'asserts': Textarea(attrs={'cols':80, 'rows':2,'wrap':'off'}),
                    'enums': Textarea(attrs={'cols':30, 'rows':5,'wrap':'off'}),
                    'enums_annotations': Textarea(attrs={'cols':50, 'rows':5,'wrap':'off'}),
                    't_code': Textarea(attrs={'cols':15, 'rows':5,'wrap':'off'}),
                    't_string': Textarea(attrs={'cols':30, 'rows':5,'wrap':'off'}),
                    't_abbrev': Textarea(attrs={'cols':10, 'rows':5,'wrap':'off'}),
                    't_version': Textarea(attrs={'cols':10, 'rows':5,'wrap':'off'}),
                    't_name': Textarea(attrs={'cols':40, 'rows':5,'wrap':'off'}),

                   }



Thanks in advance for any further guidance.  

--Tim


 

For more options, visit https://groups.google.com/groups/opt_out.

Andreas Kuhne

unread,
Feb 27, 2014, 8:18:57 AM2/27/14
to django...@googlegroups.com
Hi again Timothy,

Actually it's much easier than you think.

The error you showed is a validation error, is it not?

What you do is that you submit the form via jquery ajax, something like this should work:

  $.ajax({ type: 'POST', url: the_form_url, dataType: 'html', data: { email : $('#id_email').val(), name : $('#id_name').val(), phone : $('#id_phone').val() }, success: function(data){ $("#old_div_content").html(data); }, error: function(xhr, textStatus, errorThrown) {         console.log('AJAX communication failed:', textStatus, errorThrown); } });

Now you will have to change the function so that the parameters sent to your view are correct (in the data map), the url is correct and the success method changes the correct div. You won't have to do any error handling in jquery at all, because the validation is on the server. When you replace the html in the div that you want to replace, the user will just get the validation errors that django creates for you.

You really don't have to change anything in the view that you are using at the moment, because it already returns the information that you want in the div, all you have to do is get in into the div :-)

Regards,

Andréas


Timothy W. Cook

unread,
Feb 27, 2014, 8:50:45 AM2/27/14
to django...@googlegroups.com
Thanks Andreas.  

I'll poke around with this and see if I can figure it out.

If not;  I'll Be Back!   :-)

Cheers,
Tim




For more options, visit https://groups.google.com/groups/opt_out.

Timothy W. Cook

unread,
Feb 28, 2014, 9:48:42 AM2/28/14
to django...@googlegroups.com
On Thu, Feb 27, 2014 at 10:18 AM, Andreas Kuhne <andrea...@suitopia.com> wrote:
Hi again Timothy,

Actually it's much easier than you think.


Great news!  :-)
 

The error you showed is a validation error, is it not?


Yes.


In the example that you gave (below) it seems that I will need an AJAX function for each different form.  Correct? 
IOW:
There are 25 different forms/views/models that can be selected, one at a time, for create or update in this div.  So, do I understand correctly that I need a function with the correct URL and data map for each one of those?  If so, what is the approach to calling the one the user has selected?  My urks are named, for example: dvtemporal_create and dvtemporal_update.  Of course the _update has the record id as well.  

There is a lot of information in the Django request so I want to be able to reuse this with an 'abstract as possible' ajax function. 

Thoughts? 

--Tim 

 

For more options, visit https://groups.google.com/groups/opt_out.

Andreas Kuhne

unread,
Feb 28, 2014, 10:36:45 AM2/28/14
to django...@googlegroups.com
Hi Timothy,

What you could do is create a function that gets the id of the form. It can then query the action of the form and the parameters of the form. It would look something like this:

function submitForm(form_id) {
var $form = $("#" + form_id);

$.ajax({
type: 'POST',
url: $form.attr('action'),
dataType: 'html', data: $form.serialize(), success: function(data){ $("#old_div_content").html(data); }, error: function(xhr, textStatus, errorThrown) {         console.log('AJAX communication failed:', textStatus, errorThrown); } });
}

This way it is pretty generic as long as the "old_div_content" div id stays the same.

Regards,

Andréas



Med vänliga hälsningar,

Andréas Kühne
Software Development Manager
Suitopia Scandinavia AB


Timothy W. Cook

unread,
Mar 1, 2014, 6:28:25 AM3/1/14
to django...@googlegroups.com
Still not there yet.  There is something I am not understanding about capturing the response back from the server.   It still opens the template as an HTML page and not inside the div.  Is it possibly how I am using the HTTPResponse?  Since I am not modifying it at all. 


View:
class DvBooleanCreateView(CreateView):
    template_name = 'dvboolean_create.html'
    success_url = '/dashboard'
    model = DvBoolean
    fields = ['prj_name','data_name','lang','valid_trues','valid_falses','description','sem_attr','resource_uri','asserts',]
    form_class = DvBooleanCreateForm
    
Form:
class DvBooleanCreateForm(forms.ModelForm):
    class Meta:
        model = DvBoolean
        localized_fields = ('__all__',)
        fields = ['prj_name','data_name','lang','valid_trues','valid_falses','description','sem_attr','resource_uri','asserts',]

        widgets = {
                    'data_name': TextInput(attrs={'size':90}),
                    'description': Textarea(attrs={'cols':80, 'rows':5,'wrap':'off'}),
                    'sem_attr': Textarea(attrs={'cols':15, 'rows':3,'wrap':'off'}),
                    'resource_uri': Textarea(attrs={'cols':60, 'rows':3,'wrap':'off'}),
                    'asserts': Textarea(attrs={'cols':80, 'rows':2,'wrap':'off'}),
                    'valid_trues': Textarea(attrs={'cols':20, 'rows':5,'wrap':'off'}),
                    'valid_falses': Textarea(attrs={'cols':20, 'rows':5,'wrap':'off'}),

                   }



Template:

<script type="text/javascript" >
  $(document).ready(function($){
  $('#editbox').perfectScrollbar('update');
  });    

</script>

<script type="text/javascript" >
    $( "pct_form" ).submit(function( event ) {
    $.ajax({ 
        type: 'POST',
    url: $('pct_form').attr('action'),
    dataType: 'html',
    data: $form.serialize(),
    success: function(data){
    $("#editbox").html(data);
    },
    error: function(xhr, textStatus, errorThrown) {
           console.log('AJAX communication failed:', textStatus, errorThrown);
    }
    })});
</script>

Create a new <span title="DvBoolean complexType"><b>Boolean</b></span> Type.  * = input is required.<br />
  <form id="pct_form" method="post" action="{% url 'dvboolean_create' %}">
       {% csrf_token %}
    <div class="createform">
      <p>    
      <label for="id_prj_name" title="{{ form.prj_name.help_text }}">*Project:</label> {{ form.prj_name }}<br />
      <label for="id_data_name" title="{{ form.data_name.help_text }}">*PcT Name:</label> {{ form.data_name }}
      </p>
      <p>
      <label for="id_lang" title="{{ form.lang.help_text }}">*PcT Language:</label> {{ form.lang }} <br />    <br />
      <label for="id_description" title="{{ form.description.help_text }}">*Description:</label><br /> {{ form.description }} 
      </p>
      <table border="1" title="The number of Attributes and URIs must be exactly the same.  One per line, with no extra empty lines.">
       <caption>Semantics</caption>
  <tr><td align="center">Attribute</td><td align="center">URI</td></tr>
  <tr><td title="{{ form.sem_attr.help_text }}">{{ form.sem_attr }}</td><td title="{{ form.resource_uri.help_text }}">{{ form.resource_uri }}</td></tr>
     </table>      
      
      <p title="{{ form.asserts.help_text }}">
      Asserts:<br />{{ form.asserts }}      
      </p>

      <!-- Type Specific entries start here -->
     
     <table border="1" title="There must be at least one True and one False. The number of Trues and Falses must be exactly the same.  One per line, with no extra empty lines.">
       <caption>Boolean Sets</caption>
  <tr><td align="center">Trues</td><td align="center">Falses</td></tr>
  <tr><td title="{{ form.valid_trues.help_text }}">{{ form.valid_trues }}</td><td title="{{ form.valid_falses.help_text }}">{{ form.valid_falses }}</td></tr>
     </table>      
      <br /> 
      <input type="submit" value="Save" /><br />
    </div>
  </form>
  
 







For more options, visit https://groups.google.com/groups/opt_out.

Andreas Kuhne

unread,
Mar 1, 2014, 9:24:30 AM3/1/14
to django...@googlegroups.com
Hi Timothy,

The problem you are having now is that you haven't connected your form to the eventhandler. You are missing the "#" in the jquery call:
$( "#pct_form" ).submit(function( event ) {
    event.preventDefault();
$.ajax({ 
        type: 'POST',
     url: $('#pct_form').attr('action'),
     dataType: 'html',
     data: $form.serialize(),
     success: function(data){
     $("#editbox").html(data);
     },
     error: function(xhr, textStatus, errorThrown) {
             console.log('AJAX communication failed:', textStatus, errorThrown);
     }
    })});


I also added "event.preventDefault()" so that the default handler for the form submit won't be called. Also as a final touch, make sure that the event handler above is added within a $(document).ready(function($){} block. Otherwise the form won't exist when you try to add the event handler to the form

Regards,

Andréas


Reply all
Reply to author
Forward
0 new messages