Login Register

Dojo n00b looking for resources

I'm new to Dojo and haven't done a great deal of JavaScript. I'm upgrading some of our PHP pages to have a little more interactivity, form validation and the like. But I'm not sure how to go about doing some of the things that I need to do. I've seen several tutorials for doing bits and pieces, but haven't come across anything that's up to date or focuses on the latest Dojo.

This is what I need to do:

I have a basic user information form, with required fields. I have a series of checkboxes for what "Department" users are in. These are all passed to PHP with the id of "department_id[]" so that they come across as an array. When a user clicks on one of these, it calls a PHP page that echoes back a set of form elements common to the selected departments.

Two things I'm coming across is:

1) How do I make Dojo not submit the form if there are validation errors?
2) I'm understanding that you cannot have identical names for checkbox elements (e.g. department_id[]), what is the best way to get around this limitation?
3) How would I go about validating that the password and confirm_password fields are identical?

Thanks in advance for helping out someone just breaking into the whole DHTML world.

Okay, I've made some

Okay, I've made some progress. I've got my department ID's passing to dojo and my PHP script is creating new elements. However, the new elements do not seem to come into play with "DojoType". After doing some reading, I think this is because I'm creating them after the parser is done. The php creates elements of different types (text boxes, check boxes, etc.), some with specialized formatting, but it does this in plain html obviously. How do I dynamically create a form element and echo it out onto the page from within Dojo? Or make an element take on a dojoType attribute after it has been created?

Thanks!

Is the page doing a regular

Is the page doing a regular form submission or an XHR form submission?

If it is doing a regular form submission and the server is returning a new page, then that page should include Dojo and use dojotype on the elements.

If it is doing an XHR form submission with dojo.xhrPost or dojo.xhrGet then I believe you would have to run it through the parser. The alternatives are to use ContentPane widgets which can retrieve HTML with dojotype attributes and automatically parse it.

Any sample code would be useful.

Is the page doing a regular

Is the page doing a regular form submission or an XHR form submission?

If it is doing a regular form submission and the server is returning a new page, then that page should include Dojo and use dojotype on the elements.

If it is doing an XHR form submission with dojo.xhrPost or dojo.xhrGet then I believe you would have to run it through the parser. The alternatives are to use ContentPane widgets which can retrieve HTML with dojotype attributes and automatically parse it.

Any sample code would be useful.

Certainly, see code snippets

Certainly, see code snippets below:

This is my code on the edit account page, specifically, the js that calls the php page to update the list. All of this seems to be working, it just doesn't seem to be recognizing it as a dojoType element. It's not returning a new page, just html that's inserted into the current page. I'll have to read up on how to run things through the parser and using ContentPane widgets.

var selecteddepts = new Array();
                for (var i=0;i<document.getElementById("edit").length;i++) {
                        var theelement = document.getElementById("edit").elements[i];
                        if (theelement.checked && parseInt(theelement.value)>0) {
                                selecteddepts.push(theelement.value);
                        }
                }
               
                var url = String(window.location).split("/");
                url.pop();
                var queryString = "";
                for(i=0;i<url.length;i++){
                        queryString += url[i]+'/';
                }
                   
                var queryString = queryString + "includes/ajaxhandler.php?action=printstudentfields&user_id="+user_id+ '&department_id[]='+ selecteddepts.join('&department_id[]=');
                   
                dojo.xhrGet({
                        url: queryString,
                        load: function(data){
                            dojo.byId('customfields').innerHTML = data;
                        },
                        error: function(data){
                            dojo.byId('customfields').innerHTML = data;
                        }
                    })

This is the php page that returns the form elements:

switch($row['TYPE']){
				case("text"):		
					echo '';
				break;
				case("check"):
					... other code for different kinds of form elements.
				break;
				...
			}

I think what you're trying

I think what you're trying to do fits exactly with the functionality of the ContentPane widget.

You should first create a DOM element for the ContentPane which will be the placeholder to contain the content coming from the called HTML code snippet. You can do this programatically or declaratively.

The programmatic technique is shown here.

new dijit.layout.ContentPane( {id: "field"}, dojo.byId("parentNode"));

The above code assumes that "parentNode" is a DOM element that already exists on your page. This is the element Dojo uses to attach the new widget to.

The declarative technique for creating the new widget is shown here.

<div id="field" dojoType="dijit.layout.ContentPane">
</div>

In either case you need to ensure that the widget class is loaded by Dojo by putting the following code at the top of your page.

dojo.require("dijit.layout.ContentPane");

Now you just need to run the "setHref" method on the ContentPane widget which will create an XHR request based on "queryString" which will be passed to the method.

Dojo will automatically download the HTML containing the new element which should have the "dojoType" attribute specified and then Dojo will parse it automatically and add the new element as a child to the ContentPane widget.

In your code example, after building the "queryString" replace the "dojo.getXHR" with the following:

dijit.byId('field').setHref(queryString);

Note: There is one gotcha. Any widgets used in the HTML included in the called page must have a "dojo.required" statement in the calling page so their class definitions get loaded.

I hope this helps.

And then it was all clear.

And then it was all clear. I see how it works now... I appreciate the help. That certainly does seem to work. Now all I need to figure out is how to ensure that the form is validated before submitting. Is there a quick way to refuse the form submission if there are validation errors on the page?

Okay, so I'm working to get

Okay, so I'm working to get TabContainer and ContentPane working. I've seen a few different ways to go about this, but so far most of what I've found looks to have been the way it was done way back in 0.3-0.4 or so, and there's different methods to doing it.

Assume I have a page called panel.php that's containing the tab container. With a content-pane, I can set an href to load in a page on click, right? e.g.

But, what seems to be happening is that it's looking to run JavaScript from the parent page. Do I need to place my JS on the panel.php page for all of the functions contained within the edit_acct.php page? Should I be able to put an addOnLoad on the edit_acct.php page and have it run a function when that loaded within the main page? I've tried that and it doesn't seem to work.

Sorry if I'm asking dumb n00b questions, but I have been looking for days and haven't been able to find anything useful here.

Thanks!

My understanding is that you

My understanding is that you would have to put the JavaScript in the calling page even though it is used on the called page. And if you are using any new widgets on the called page, you would also have to do a dojo.require for the new widgets on the calling page.

To have the content refreshed when the tag is selected, use the "refreshOnShow" property in the ContentPane as shown below.

<div id="mainTabContainer" dojoType="dijit.layout.TabContainer" style="width: 100%; height: 7em;">
    <div id="tab2" dojoType="dijit.layout.ContentPane"
         href="dynamic.html"
         refreshOnShow="true"
         title="Tab 2" selected="true">

    </div>
</div>

Sounds good. It seems like

Sounds good. It seems like it would be more efficient to be able to store javascript in the page being called as well, but I understand the limitation. There is one other thing. The page being called needs a function run on it to update a field. Right now, I have an onchange on some of the checkboxes that call it. That works fine, but I can't seem to figure out how to call it on page load. If I put addOnLoad in the calling page, it does nothing because the page in the tab hasn't been called yet. If I put it in the called page, say, in a script tag, it doesn't run. can I do something like dojo.byId("tab1").addOnLoad(updatelist)?

Sounds good. It seems like

Sounds good. It seems like it would be more efficient to be able to store javascript in the page being called as well, but I understand the limitation. There is one other thing. The page being called needs a function run on it to update a field. Right now, I have an onchange on some of the checkboxes that call it. That works fine, but I can't seem to figure out how to call it on page load. If I put addOnLoad in the calling page, it does nothing because the page in the tab hasn't been called yet. If I put it in the called page, say, in a script tag, it doesn't run. can I do something like dojo.byId("tab1").addOnLoad(updatelist)?

Another issue that I seem to

Another issue that I seem to be running into now is dynamically changing the contents of a tab (contentPane). I can change it using setHref to something else, but when trying to update the contents back to my original content (e.g. a back button), it doesn't work. I believe this is because it duplicates the names of the form elements. I found reference to a method called destroy (e.g. - dojo.byId('tab4').destory(); dojo.byId('tab4').setHref('url.php');), but that doesn't seem to do anything.

Use 'dojox.layout.ContentPane' instead of dijit

Hi kepardue...

I went through exactly what you're going through a few days ago. Just like you are now doing, I originally ended up throwing stuff into the parent page, that I really wanted to put in the page getting loaded into the ContentPane. I spent a couple of hours reading many posts (many people have this issue). I found the old (pre 0.9) feature-laden version of ContentPane, with many options I wanted, but that had been removed in the "simplified" dijit version in 0.9 and beyond. Finally, I found the solution on this long thread (but I'll summarize below for ya): http://www.dojotoolkit.org/forum/dijit-dijit-0-9/dijit-support/executesc...

So, a good solution is to use the dojox.layout.ContentPane rather than the dijit.layout.ContentPane. If you read the thread ref'd above, you'll see that the programmer took the good stuff from the old contentpane. The good stuff being "executeScripts=true". Add that property & require in the dojox version & you're in business -- it will work like you think it should, parsing & executing script tags, which should also solve your addOnLoad quandry. Here's a working example fragment of the dojox version inside an accordian pane that I'm using successfully:

<!-- Accordian Pane Widget - Panel #1 - List of Jobs Tree Widget -->
<div dojoType="dijit.layout.AccordionPane" title="Job Explorer">
      <div dojoType="dojox.layout.ContentPane" class="soria" href="jobs.html" executeScripts="true"> </div>
</div>

I know the Dojo guys are busy & are focused on fixing the docs, so something to live with for the moment until they can catch up...or until I end up with an FAQ :-) The current FAQ is not very useful IMHO, occasionally the Dojo Book might be a little short or missing a few bits & pieces here & there .... you end up doing a search, but you find something from v0.4, which, of course doesn't work or has changed slightly. The website Search doesn't seem to be able to narrow down by date (surely there's a way...), etc. A bit frustrating, but seems to be improving quickly. I did actually throw a short post onto the Dojo Book, ContentPane section, about this issue, but it's in there amongst a bunch of other posts, so easy to miss. (FYI, dijit.Tooltip has the same doc/version issues as this -- I dropped a post on the end of that earlier today) .

Sorry for the lengthy post, curse of a fast typist... good luck...

Keep it real,
Dylan Tynan
noob++

Thanks very much for the

Thanks very much for the feedback! The slight variations in how things are done have been a frustration to me as well, but hopefully now things will solidify around the 1.0 way of doing things. I'm holding out for the Definitive Guide to Dojo to come out in a bit, hopefully that'll have all the post-1.0 syntax and best practices I need.

Thanks again! I'll work with Dojox for a bit and see if I can hammer it out!

Okay, I've got one last

Okay, I've got one last issue that seems to keep me from working. I've been looking for three days trying to figure this out because it seems to be a common problem. But, there either aren't any clear solutions posted or I don't understand the solutions due to my lack of experience with the framework. I'm trying to dynamically update the contents of my ContentPane (using setHref), but when I do so it complains that my ID has already been used and refuses to parse another one. I know *why* this is happening, it's not unregistering the widget after I change my content then try to change it back to the original fields. What I haven't been able to find is how to get around it.

I've seen dijit.byId('tab4').destroyRecursive which destroys the widget and all of the widgets contained in it, and I've seen what seems to be more appropriate, destroyDescendants() which destroys all of the widgets contained in the ContentPane but leaves the ContentPane in tact... but, this latter solution doesn't seem to do anything.

Any hints on how to do this?

Hmm.

I don't know the answer to that... what is the exact msg you're getting? I seem to remember seeing some issue, when I was using the dojox.layout.ContentPane (w/executeScripts=true), where there was something about...hmm, something like I had already pulled in a js file via script in my main doc, then it tried again in the lower doc (the one in the ContentPane), and I got some error .... or, it could have been CSS files. One of the two. There was a forum post where someone mentioned it, but I can't find it now. Could it be something like that? If so, maybe you're error msg will ring a bell....

Dylan Tynan

The specific error is:

The specific error is: Couldn't create widgets in *my content pane id* from *my file location* [ Error: Tried to register widget with id==*my widget id* but that id is already registered ]

Seems to happen when you dynamically refresh the contents of a contentPane. I'm refreshing them using setHref.

As an update, I was hoping

As an update, I was hoping that I would be able to accomplish what I need to do by destroying the content pane and then re-adding the pane with the original URL. Using some help from another post as a guide:

dijit.byId('tab4').destroy();
var cpane = new dijit.layout.ContentPane({href: 'modules/admin/fpr.php?id=<?php echo $id; ?>&step=3'}, dojo.doc.createElement('div'));
dojo.body().appendChild(cpane.domNode);
cpane.startup();

But... this seems to cause the same issue. This seems to be a common problem that people have between 0.9 and 1.0... but I really can't find a common solution to it. Some people seem to have gone in and modified the Dojo source, but I'm not comfortable enough with the toolkit yet to be making changes like that to it. Any advice?

Bump... I'd really like to

Bump... I'd really like to figure this out soon.

Let me go back to basics a bit. Maybe I'm just not taking the right approach to this. In my application, I want to have a tabbed window where the contents of the tab automatically expand to take up the necessary vertical length (e.g., no scrollbars)--I still haven't accomplished this.

One tab will be the User Account, followed by Enrollment, and a Test Result tab. I've gotten most thing working except the Test Result tab, which consists of a dropdown menu that lets the user select a test which loads the test results (allowing an administrator to change them). From that page, the admin can either submit the modified results and go back to the previous screen, or click on the "View History" link to show the past changes and who made them. My problem is that refreshing the content here doesn't parse the widgets.

Should I be taking a different approach?

bump, same problem

having same issue. someone pls help

i saw similar stuff at one time

I had an HTML page with a tabcontainer, each tab loading another HTML page using the dojox.layout.ContentPane with the executeScripts=true. I had a calendar widget on each page that was loaded in via the ContentPanes. It seemed like a good way to work up some sample type pages really quickly. However, I made the mistake of having the same id=XXXX on each Calendar, so I received that same msg (or something similar). Perhaps you're seeing the same thing? I just went in and changed the IDs for the conflicting stuff & it worked fine. However, that's not a good solution for a real project, since you're ending up with everything loading into the global environment I think. Instead, you probably want to use dojo.declare & make a class so you get a namespace to protect from content loaded in other panes. I think the old, 0.4x version, of ContentPane offered some sort of namespace-specifier or something - perhaps that's still in there in the dojox version & then you could short-cut that way (assuming that the conflict is between the various content panes ... I guess you might also just have multiple widgets w/same name on one of those pages ... class/template in that case I think).

D

More thoughts....

Ok, I went back through & reread this thread. At this point, it's a little unclear which code/methods are producing which problems exactly, so if you get a chance to restate w/xample that might be good at this point, just in case.... That said, got a couple of ideas that might lead somewhere, or maybe not, but we can see.

The re-registering ID problem is either what I was doing, actually using widgets with the same hard-coded IDs (duh) that, at some point, both attempt to be alive at the same time. Or, the dojo parser is getting re-run somehow & trying to instantiate widgets w/same ID --- actually, this was actually my problem I think (dojox.layout.contentpane). Or, your destroy isn't working. Or, something tricky is happening when you create that contentpane ..... I thought I'd read something about it cloning a node, so perhaps something around that... OR, fnally, your PHP echo ID thing isn't as unique as you think perhaps. The error occurs at the cpane.startup()? Perhaps you should get the PHP id ahead of time (before creating the node), make the ID string, then try to dijit or dojo byID that string, console.dir() the results of that & see what the conflict is.

I noticed in your example that you're destroying a tab container, but then adding the new node to the body tag, rather than under a new tab. Probably doesn't matter. I wonder if there's more magic in the built-in dojo template-ID-widget-creation stuff than one might think ... maybe nix the php ID incrementer & use a ${id} thingy, though that seems unlikely to make much difference.

I think your best bet is judicious use of Firebug, plenty of console.dirs, the DOM inspector, etc. and figure out exactly what Id you're creating that is conflicting .... the act of doing that might lead the problem perhaps.

Have you tried the latest dojo code? Incidentally, why do you need to destroy & then recreate the same nodes with the same URLs? Are you just trying to clear the displayed content of the pane or something? Ohhh, right, because you're loading a URL & it's not re-updating, is that why? Have you watch Firebug closely to see it's really re-getting the content. Even though you have a URL with a query-string, perhaps it's still getting cached since you're re-requesting the same URL over again. I think there's a preventCache=true or something maybe? To be sure, I'd just tell IE to check-everytime, for the moment, to see if that's it....

Dylan Tynan

to follow up on your initial

to follow up on your initial comment, I would suggest moving this discussion into a new forum topic, with a title indicitive of the problem, starting over explaining the current state. I too am confused about what is going on in these 20-some-odd unthreaded posts ... or what the problem is, and find it hard to read back and catch up (there's a lot going on here it looks like) ;)

Regards