using ajax and load for modular applications

187 views
Skip to first unread message

angle

unread,
Jun 1, 2012, 9:07:21 AM6/1/12
to web...@googlegroups.com
Hi web2py,

I am a fairly experienced coder, but am new to web-programming and web2py.
Ihave read the documentation, bought the book, and done quite a few of the
examples which have run OK. I am coding on Windows7 OS - using
Firefox browser.

I am trying to modularise my current demo web2py web-app, so that when i click
on a webGrid (a 'view' link) on the right-hand-side of page, my column on the
left-hand-side of the page updates to show the details of the selected
patient/scan row. Before trying this, I have got it to work so the whole page
updates when I click on that link, but to progress this further, I want only
the left-hand column to update. I am trying to adapt the example from the book
(Chapter 2 - Designing Modular Applications) and the example from the
'Components' section of the online docs
(http://web2py.com/books/default/chapter/29/12).

Currently, the initial index page loads OK, with the left hand column showing
the default (scanId=1) record. It's the click on 'view' which doesn't work. I
am trying 2 options and they both give me a blank 'none' page, when I click
on the 'view' link. I can't figure out the mistake I am making and have been
working on it for over a day now. The code is below.

As you can see, I think its because I am still unclear on how the load and
'response.ajax = 'web2py_component(' calls work.
Hope you can help.

angle



******************************
******* DEFAULT.PY ********
******************************

def index():
import webgrid
from gluon.tools import Crud
crud = Crud(icc_db)
grid=webgrid.WebGrid(crud)
grid.datasource = icc_db(icc_db.scan.id>0)
grid.pagesize = 20
grid.action_links = ['view']
grid.action_headers = ['view']
grid.enabled_rows = ['header','pager','footer']
grid.crud_function = 'view'


#if request.controller == 'default' and request.function == 'index':
# if request.args:
# crud.settings[request.args(0)+'_next'] = URL('index')


return dict(grid=grid())

def view():
vars1={'scanId':(request.args[2])}

##### THIS IS WHERE I AM TRYING VARIOUS OPTIONS - RETURN 'NONE' page ####


LOAD('default','post.load',ajax=True,target='patient',vars={'scanId':(
request.args[2] or 1)})

#response.ajax = \
'web2py_component("%s","patient",ajax=True,vars=vars1)' % URL
('patient')

#response.ajax =
'web2py_component("post.load",ajax=True,target="patient",vars={"scanId":(
request.args[2] or 1)})' % URL ('patient')


def post(): #This works OK...

patientId = (icc_db(icc_db.scan.id ==
request.vars.scanId).select(icc_db.scan.patient_fk)[0].patient_fk or -1)

...

return dict(patientScanRecs = patientScanRecs,
scanImageRecs = scanImageRecs)

...

************************************************************************
* Views/Layout.html (webGrid + the left column) *
************************************************************************

<div id="displayBox_centre">
{{=grid}}

</div>

<div id="displayBox_left">
{{ if request.args: }}
{{ =LOAD('default','post.load',ajax=True,target='patient',vars=
{'scanId':(request.args[2] or 1)}) }}
{{ else: }}
{{
=LOAD('default','post.load',ajax=True,target='patient',
vars={'scanId':1}) }}
{{pass}}

</div>

************************************
****** Views/default/post.load ******
************************************

<H2> Patient ID: {{=patientScanRecs[0].patient.id}} </H2>
<H2> Diagnostic Group: {{=patientScanRecs[0].patient.DiagnosticGroup}}</H2>
<H2> Source:{{=patientScanRecs[0].patient.Source}} </H2>

<div class="scanList">

{{for patient_scan in patientScanRecs:}}
<div class="scan">
<H2>Age at Scan {{=patient_scan.scan.ageAtScan}}</H2>
<H2>Date of Scan {{=patient_scan.scan.dateOfscan}} </H2>
<div class="scanImageList">
{{for scan_image in scanImageRecs:}}
...
{{pass}}
</div>
</div>
</div>
{{pass}}

</div>




Anthony

unread,
Jun 1, 2012, 12:10:28 PM6/1/12
to web...@googlegroups.com
LOAD('default','post.load',ajax=True,target='patient',vars={'scanId':(
  request.args[2] or 1)})

LOAD is an HTML helper that generates a div and a script element, so it should be inserted in a view, not simply called in the controller.
 
  #response.ajax = \
    'web2py_component("%s","patient",ajax=True,vars=vars1)' % URL
('patient')

I think this should be response.js rather than response.ajax. Also, response.js is only used if the action that sets it is being called as a web2py component -- is that the case here? Finally, web2py_component() does not take an ajax or vars argument. If you want vars included in the URL, then pass it to the URL function.

Anthony

angle

unread,
Jun 1, 2012, 2:03:23 PM6/1/12
to web...@googlegroups.com
Thanks for your response, I've answered your points below: 
 
  #response.ajax = \
    'web2py_component("%s","patient",ajax=True,vars=vars1)' % URL
('patient')
I think this should be response.js rather than response.ajax.

This code is copied from the example 'Designing Modular Applications' on page 94 of the web2py book.  In that example it is called when a forms 'onaccept' event is triggered. In my code it is called in my 'viewPatient' function that is called by setting the webGrid's crud_function... (grid.crud_function = 'viewPatient'). I thought that these were similar calls, so that response.ajax should work in the same way. Are they not the same? ???

 
Also, response.js is only used if the action that sets it is being called as a web2py component -- is that the case here?
 
I believe so, but I am not 100% sure. It appears that the response.ajax is being set via a call to 'web2py_component(...)' . Is that correct?

 
Finally, web2py_component() does not take an ajax or vars argument. If you want vars included in the URL, then pass it to the URL function.

The URL is pointing to a div element -  (as in the example from the book). I've tried 'URL('patient', vars=vars1)' (whilst assigning to response.ajax and response.js) and I get a 'not all arguments converted during string formatting' error.



 

Anthony

unread,
Jun 1, 2012, 3:01:02 PM6/1/12
to web...@googlegroups.com
On Friday, June 1, 2012 2:03:23 PM UTC-4, angle wrote:
Thanks for your response, I've answered your points below: 
 
  #response.ajax = \
    'web2py_component("%s","patient",ajax=True,vars=vars1)' % URL
('patient')
I think this should be response.js rather than response.ajax.

This code is copied from the example 'Designing Modular Applications' on page 94 of the web2py book.

Unfortunately, I think there are a number of errors in that example, one of which is that it should be response.js, not response.ajax.
 
  In that example it is called when a forms 'onaccept' event is triggered. In my code it is called in my 'viewPatient' function that is called by setting the webGrid's crud_function... (grid.crud_function = 'viewPatient'). I thought that these were similar calls, so that response.ajax should work in the same way. Are they not the same? ???

In the book example, response.ajax (which should be response.js) is set in the edit_items() function, which is always called as an Ajax component. You are setting it in your view() function, but I can't see where that function is actually called, so I don't know if it is being called as an Ajax component or as a regular web page.
  
Also, response.js is only used if the action that sets it is being called as a web2py component -- is that the case here?
 
I believe so, but I am not 100% sure. It appears that the response.ajax is being set via a call to 'web2py_component(...)' . Is that correct?

No, you are setting response.ajax to "web2py_component(...)" -- that's not what I'm talking about. The question is whether the function in which response.js is being set is itself being accessed by a call to web2py_component() on the client side. It is being set in your view() function, so the question is how is the view() function being called?

Finally, web2py_component() does not take an ajax or vars argument. If you want vars included in the URL, then pass it to the URL function.

The URL is pointing to a div element -  (as in the example from the book).

I think there is an error in the book -- it mistakenly builds a URL that refers to a div id rather than the name of the controller function. Is that what you're talking about?
 
I've tried 'URL('patient', vars=vars1)' (whilst assigning to response.ajax and response.js) and I get a 'not all arguments converted during string formatting' error.

Show the full code.

Anthony 

Andrew

unread,
Jun 1, 2012, 3:21:11 PM6/1/12
to web...@googlegroups.com
Also, I don't see a div with an Id = patient. That's your target. Is it in the code but not in your post?

angle

unread,
Jun 2, 2012, 9:58:00 AM6/2/12
to web...@googlegroups.com
Thanks for your comments. I'll answer each one below, along with the answer to Andrew's question in a seperate message.
+ Full code, and results of view page source (for successful opening page) are attached.



On Friday, June 1, 2012 8:01:02 PM UTC+1, Anthony wrote:
On Friday, June 1, 2012 2:03:23 PM UTC-4, angle wrote:
Thanks for your response, I've answered your points below: 
 
  #response.ajax = \
    'web2py_component("%s","patient",ajax=True,vars=vars1)' % URL
('patient')
I think this should be response.js rather than response.ajax.

This code is copied from the example 'Designing Modular Applications' on page 94 of the web2py book.

Unfortunately, I think there are a number of errors in that example, one of which is that it should be response.js, not response.ajax.

OK thanks, I'll keep it as response.js.

 
  In that example it is called when a forms 'onaccept' event is triggered. In my code it is called in my 'viewPatient' function that is called by setting the webGrid's crud_function... (grid.crud_function = 'viewPatient'). I thought that these were similar calls, so that response.ajax should work in the same way. Are they not the same? ???

In the book example, response.ajax (which should be response.js) is set in the edit_items() function, which is always called as an Ajax component. You are setting it in your view() function, but I can't see where that function is actually called, so I don't know if it is being called as an Ajax component or as a regular web page.

[[NB: To avoid confusion, in the code (included below) I've updated this function name to be viewPatient().]] 
This viewPatient() function is set as the webGrid.crud_function property, within my index() function of default.py....
(grid.crud_function = 'viewPatient'). I believe the answer to your question is that it is called as a regular webpage,
as webGrid is not an ajax component.
  
Also, response.js is only used if the action that sets it is being called as a web2py component -- is that the case here?
 
I believe so, but I am not 100% sure. It appears that the response.ajax is being set via a call to 'web2py_component(...)' . Is that correct?

No, you are setting response.ajax to "web2py_component(...)" -- that's not what I'm talking about. The question is whether the function in which response.js is being set is itself being accessed by a call to web2py_component() on the client side. It is being set in your view() function, so the question is how is the view() function being called?

See last answer above. Sorry about the confusion.

Finally, web2py_component() does not take an ajax or vars argument. If you want vars included in the URL, then pass it to the URL function.

The URL is pointing to a div element -  (as in the example from the book).

I think there is an error in the book -- it mistakenly builds a URL that refers to a div id rather than the name of the controller function. Is that what you're talking about?

Yes. Since reading your comments, and looking at the page-source for the (successful) initial index page upload, I've updated this to:

response.js = \
  'web2py_component("/ICC_Data_Management/default/post.load?scanId=4","patient");' \
  % URL('/ICC_Data_Management/default/post.load?scanId=4')

... and this returns the error:   '<type 'exceptions.SyntaxError'> not enough information to build the url'






+ to answer the question from Andrew, in a seperate message:
---'Also, I don't see a div with an Id = patient.  That's your target.   Is it in the code but not in your post?'

From the example in the book, it appears (to me) to imply that the '{{=LOAD('default', 'list_items', ajax=True, target='showItems')}}' call in the html, automatically creates a div id='showItems'.  This was further evidenced by my own application, where I do not explicitly create a div tag with id=patient, but when I view pagesource for my opening page (which works OK) and has the call 
{{ =LOAD('default','post.load',ajax=True,target='patient',vars={'scanId':1}) }}, the resulting page source does include a '<div id="patient">loading...</div>' element.



 

 
web2pyCode-forQuestion.txt

Andrew

unread,
Jun 2, 2012, 10:13:58 AM6/2/12
to web...@googlegroups.com
I didn't know that. I've always specified so that I could control where in the HTML it would go.

Anthony

unread,
Jun 2, 2012, 10:50:56 AM6/2/12
to web...@googlegroups.com
In the book example, response.ajax (which should be response.js) is set in the edit_items() function, which is always called as an Ajax component. You are setting it in your view() function, but I can't see where that function is actually called, so I don't know if it is being called as an Ajax component or as a regular web page.

[[NB: To avoid confusion, in the code (included below) I've updated this function name to be viewPatient().]] 
This viewPatient() function is set as the webGrid.crud_function property, within my index() function of default.py....
(grid.crud_function = 'viewPatient'). I believe the answer to your question is that it is called as a regular webpage,
as webGrid is not an ajax component.

OK, in that case, setting response.js in viewPatient() won't have any effect (by the way, Python prefers view_patient rather than camel case for functions and variables -- http://www.python.org/dev/peps/pep-0008/#prescriptive-naming-conventions). If viewPatient() is simply called as a regular full web page, then to run some JS on the page when it loads, you'll have to add a script element with the JS code inside a jQuery document ready. In this case, though, that's not necessary because it appears you simply want to load a web2py Ajax component on that page, which you can simply do by including the LOAD() helper in the viewPatient view.

More generally, it does not appear that what you are trying to do exactly mirrors the structure of the book example you are copying, so you might be better off ignoring that example. Instead, be sure to read http://web2py.com/books/default/chapter/29/12#Components. The cookbook is generally more advanced and assumes a firm understanding of how the framework works. Attempting to alter the examples without understanding the underlying functionality is not likely to be a fruitful approach.

Yes. Since reading your comments, and looking at the page-source for the (successful) initial index page upload, I've updated this to:

response.js = \
  'web2py_component("/ICC_Data_Management/default/post.load?scanId=4","patient");' \
  % URL('/ICC_Data_Management/default/post.load?scanId=4')

... and this returns the error:   '<type 'exceptions.SyntaxError'> not enough information to build the url'

You are passing a fully constructed url to the URL() function -- that's not how it works. You probably want:

response.js = 'web2py_component("%s", "patient");' % URL('default', 'post.load', vars=dict(scanId=4))

But as mentioned above, response.js isn't really appropriate in this case.

+ to answer the question from Andrew, in a seperate message:
---'Also, I don't see a div with an Id = patient.  That's your target.   Is it in the code but not in your post?'

From the example in the book, it appears (to me) to imply that the '{{=LOAD('default', 'list_items', ajax=True, target='showItems')}}' call in the html, automatically creates a div id='showItems'.  This was further evidenced by my own application, where I do not explicitly create a div tag with id=patient, but when I view pagesource for my opening page (which works OK) and has the call 
{{ =LOAD('default','post.load',ajax=True,target='patient',vars={'scanId':1}) }}, the resulting page source does include a '<div id="patient">loading...</div>' element.

Yes, this is correct. If you call LOAD() without specifying a target, it will generate a div with a random id, but if you specify a value for target, it will use that value as the id for the div it generates. Note, if you just call web2py_component() by itself on the client side, it will not generate the div for you, so the div must already exist on the page in that case (the LOAD() helper is executed on the server side when the page is first requested and generates the div at that time).

Anthony
Reply all
Reply to author
Forward
0 new messages