Javascript problems from a lightweight - xmlhttprequest and html fragments

P

Phil_Harvey

I am redoing my website and trying to get it to do something more
exciting using Javascript. I did normal Java at university and code at
work in VB.NET. I have got reasonably far into what I want to do but am
having some issues.

Firstly
I am using an XmlHttpRequest to pull html fragments out of files and
wish to put them into the main doccument inplace of a <span></span>
which has a given id. The user enters a "command" into a TextField and
when the onchange event is thrown I am using the contents of the text
field in a switch statement to decide which fragment should be loaded.
This works ok when TAB is pressed to throw the onchange event, apart
from the text field losing focus (which I don't want). However when
return or enter are pressed the fragment is loaded and placed in the
correct place, then the page seems to reload or refresh and loses it
again. To make this work will I need to store the loaded data so it
gets displayed again on the <body onload> event? I need someway of
getting around this refresh issue.

Secondly I get a strange duplication of information when the fragment
is loaded. The top part (main fragment that is loaded with the <body
onload> event. It does not get duplicated as text, but as some strange
unselectable object.

Ill try and get some dribbles of code up soon but I am not writing this
from my development machine.

Any help would be greatly appretiated.

Oh and can some one tell me, what is the life of a javascript variable?
Does it survive past refresh? When the script is loaded is that version
of it always used for the viewing session or does each refresh destroy
everything? If it does destroy everyting what is the best place to
store stuff - will I have to use a cookie?

Cheers
Phil.
 
T

Thomas 'PointedEars' Lahn

Phil_Harvey said:
I am redoing my website and trying to get it to do something more
exciting using Javascript. I did normal Java at university

Java != JavaScript.
[...]
I am using an XmlHttpRequest to pull html fragments out of files and
wish to put them into the main doccument inplace of a <span></span>
which has a given id. The user enters a "command" into a TextField and
when the onchange event is thrown I am using the contents of the text
field in a switch statement to decide which fragment should be loaded.
This works ok when TAB is pressed to throw the onchange event, apart
from the text field losing focus (which I don't want). However when
return or enter are pressed the fragment is loaded and placed in the
correct place, then the page seems to reload or refresh and loses it
again.

You are merely describing that the form is "submitted to itself". My
educated guess would be that you have placed the input[type=text] element
within a `form' element, and the `action' attribute of that `form' element
is not set (which is not Valid), or it is "" (the empty URI reference,
which refers to the referring resource).

What you are describing would be the behavior the user expects then, and you
should not attempt to mess with that. You should instead provide for a
server-side solution that is triggered then to process the submitted form
data in case (viable) XMLHTTP request support is not present on the client.
For the opposite case, you want to cancel the submit event of the form.
Search the archives about that.
To make this work will I need to store the loaded data so it
gets displayed again on the <body onload> event?
No.

I need someway of getting around this refresh issue.

See above. Another alternative is not to use a `form' element, but that
would not degrade gracefully anymore.
Secondly I get a strange duplication of information when the fragment
is loaded. The top part (main fragment that is loaded with the <body
onload> event. It does not get duplicated as text, but as some strange
unselectable object. [...]

I cannot make an educated guess about this until you show some code.
Oh and can some one tell me, what is the life of a javascript variable?

A variable ceases to exist when the execution context it was declared in
is exited.
Does it survive past refresh?

No, as reloading the resource exits the global execution context associated
with it.
When the script is loaded is that version of it always used for the
viewing session or does each refresh destroy everything?
Yes.

If it does destroy everyting what is the best place to store stuff -
will I have to use a cookie?

No, you do not have to. You can also use a frameset document, which
provides a different global execution context. And you can submit
information within the query-part of the request URI (HTTP GET request),
and also the request message body (HTTP POST request).

Since you probably want a server-side application as fallback, and
apparently you have a `form' element already, that is done already.
All you need to do now is to process the submitted information.


PointedEars
 
P

Phil_Harvey

Hi PointedEars,
Java != javascript - Point taken.

Here is the main function that I am calling from a switch statement
earlier in the code

function insert(url,id)
{
var element = document.getElementById(id)
try
{
req = new XMLHttpRequest();
req.open('GET', url, false);
req.send(null);
returnedText=req.responseText;
}
catch(e)
{
returnedText='Unable to retrieve data on that currently'
}

if (lastCommand=='')
{
element.innerHTML = previous+req.responseText;
if (!(url=='frag_home.htm'))
{
previous+=returnedText;
}
}
else
{
var extra = '<table width="80%" border="0" cellpadding="0"
cellspacing="0" bgcolor="#000000">' +
'<tr><td>> ' + lastCommand + '</td></tr>' +
'</table>' + returnedText;
element.innerHTML = previous + extra

if (!(url=='frag_home.htm'))
{
previous+=extra
}
}

}

<form id="frmCommandLine" name="Command Line" method="post"
style="background-color:#000000">
<label>&gt;
<input name="tf_command" type="text"
style="background-color:#000000; border:none; color:#FFFFFF;
font:'Courier New', Courier, monospace';"
onchange="doCommand(tf_command.value);tf_command.value=''" size="100"/>
</label>
</form>

As you can see your guess was correct I am not using the 'action'
attribute of the form. THe behaviour may be what the user expects in a
normal webpage, but that is not what I am trying to create. I need to
dynamically add fragments of HTML to the main page as the user types
commands.

When you say I should have a server side solution, how do you mean? The
forms action attribute should call ....what exactly? I am afraid you
have lost be a little here.

Where you suggest that I should use a frameset, are you suggesting that
I load the jscript in one frame then make it alter the other frames, so
the main frameset execution context does not get refreshed each time?
Since you probably want a server-side application as fallback, and
apparently you have a `form' element already, that is done already.
All you need to do now is to process the submitted information.

I am afraid I don't follow. I am not so familiar with the difference
between server side and client side with jscript. I already have a
form, yes, but that is part of the page the client sees.

Sorry for my ignorance

but thank you very much for your help
Cheers
Phil Harvey
 
P

Phil_Harvey

Although that is currently broken because I am trying to make the
response write work
 
T

Thomas 'PointedEars' Lahn

Phil_Harvey said:
function insert(url,id)
{
var element = document.getElementById(id)

End this assignment with an ";" (code style, avoids unexpected
effects with automatic semicolon insertion by the script engine),
and do a feature test before you call the method.
try
{
req = new XMLHttpRequest();

This will fail in IE < 7. The entire code will break in IE < 5,
despite of and because of the try..catch exception handling.
req.open('GET', url, false);

You want to consider asynchronous requests, as synchronous ones
lock up the user agent:

var returnedText;
...
req.open('GET', url);
req.onreadystatechange = function()
{
if (req.readyState == 4 && /^2|0/.test(req.status))
{
returnedText = req.responseText;
req = null;
}
};

req.send(null);

(Of course you will have to queue commands somehow then.)
req.send(null);
returnedText=req.responseText;

The identifier is not declared so far, therefore a property of the Global
Object is modified or created. Bad style.
}
catch(e)
{
returnedText='Unable to retrieve data on that currently'
;

}

The better approach is not to running the risk of throwing the exception,
but to do a feature test before you use the feature.

// in global context
var _global = this;

// in global or local context
function isMethod(a)
{
var t;
return (a && ((t = typeof a) == "function" || t == "object"));
}

var req = null;

if (isMethod(_global.XMLHttpRequest))
{
req = new XMLHttpRequest();
if (req)
{
req.open('GET', url, false);
req.send(null);
var returnedText = req.responseText;
}
}
else
{
// ActiveX/COM solution for IE,
// see http://jibbering.com/2002/4/httprequest.html
}

if (req)
{
if (lastCommand=='')

It would be simpler if you used

if (!lastCommand)

This will yield `true' if lastCommand was not initialized yet or is the
empty string, `false' otherwise (as it is supposed to be a string value).
{
element.innerHTML = previous+req.responseText;

Note that `innerHTML' is a proprietary property, so at least you want to
feature-test it before you use it. At most, you want to target Web
standards first, and use `innerHTML' and other proprietary features only
as fallback.
if (!(url=='frag_home.htm'))

if (url != 'frag_home.htm')

{
previous+=returnedText;

Push to and join an array instead.

var a = new Array();
...
a.push("...");
...
... a.join("") ...
}
}
else
{
var extra = '<table width="80%" border="0" cellpadding="0"
cellspacing="0" bgcolor="#000000">' +

Don't use presentational attributes anymore; use CSS. And if you provide
the background color, always provide the foreground color, and vice-versa.

'<tr><td>> ' + lastCommand + '</td></tr>' +
^[1] ^^[2]^
[1] Is this by intention?
'</table>' + returnedText;
^^[2]

[2] You must escape ETAGO delimiters (`</'), preferably with `<\/',
iff you use them within the HTML `script' element.
element.innerHTML = previous + extra

First concatenate (or join) the string values, then assign them to
`innerHTML'.
if (!(url=='frag_home.htm'))

See above.
{
previous+=extra

; and see above.

Don't use tabs to indent code, at least not when you post it; use
multiples of two spaces.
<form id="frmCommandLine" name="Command Line" method="post"

Probably your `form' element does not need an ID or a name. And, as I said,
if you omit the `action' attribute, the resulting markup is not Valid.
style="background-color:#000000">

So you know about CSS after all. See above.
<label>&gt;

A `label' element does not make much sense if it is not specified what it
is labeling. Give your input element an ID, then use

<input name="tf_command" type="text"
style="background-color:#000000; border:none; color:#FFFFFF;
font:'Courier New', Courier, monospace';"

You want to move that to a declaration in a `style' element or to an
external stylesheet to avoid such spaghetti code. Remove any newlines in
the attribute value, and declare the default stylesheet language, if you
don't:

onchange="doCommand(tf_command.value);tf_command.value=''" size="100"

This is also something that should be moved into a `script' element or
an external script resource to avoid spaghetti code.

Remove any newlines from the attribute value, and declare the default
scripting language, if you don't:


Your markup is (currently invalid) HTML, not XHTML. In HTML, "<.../>"
equals "<...>&gt;" (HTML SHORTTAG syntax). Besides, IE does not support
XHTML, and you do not need it here, so serve HTML 4.01 as text/html, and
omit the trailing "/" for elements with empty content.

As I said, this `label' element does not make any sense.
</form>

As you can see your guess was correct I am not using the 'action'
attribute of the form.

Which is not Valid. said:
THe behaviour may be what the user expects in a normal webpage, but that
is not what I am trying to create. I need to dynamically add fragments of
HTML to the main page as the user types commands.

As I said, you want to cancel the submit event of the form if the required
script support is present. If not, the server-side application should take
over.
When you say I should have a server side solution, how do you mean?
The forms action attribute should call ....what exactly? [...]

For example:

function makeXMLHttpRequest()
{
var req = null;
...
return req;
}

<form action="foobar.php" onsubmit="return !makeXMLHttpRequest();">
...
Where you suggest that I should use a frameset, are you suggesting that
I load the jscript in one frame then make it alter the other frames, so
the main frameset execution context does not get refreshed each time?
Exactly.


I am afraid I don't follow. I am not so familiar with the difference
between server side and client side with jscript.

JScript != JavaScript. Besides, although possible, the corresponding
server-side application does not need to be written in any ECMAScript
implementation. I preferred PHP, for example.
I already have a
form, yes, but that is part of the page the client sees.

So either you do not want to use a `form' element, only form controls (which
is perfectly Valid); AFAIS, nothing is submitted then if one presses
Return/Enter. Or, if you want to use the form it, which I recommend,
following the concept of graceful degradation, you should provide for a
server-side fallback in case one of the features used for client-side
processing of the input is not available.
[...] thank you very much for your help

You are welcome.


PointedEars
 
P

Phil_Harvey

Thanks for your help, you have been most fecund.
I will digest it and come back when I have see what I can do with your
advice. I realise that my CSS is not consistent and I forget the odd
";" here and there.
I am trying to change the way the page works now, because of your
adive.

Thanks again
Phil.
 
P

Phil_Harvey

I have it working now. The site has no content so I won't post it yet.
I have one more question....

How do I make Javascript force focus onto the text field when the page
loads? The javascript cant "see " the text field.

Cheers
Phil.
 
T

Thomas 'PointedEars' Lahn

Phil_Harvey said:
How do I make Javascript force focus onto the text field when the page
loads? The javascript cant "see " the text field.

It can "see" it if the code to access it is called when the `load'
event occurs. However, I strongly recommend against imposing your
idea of positioning the system pointer on your users. If you do,
you will hinder or prevent keyboard-based scrolling, for example.


PointedEars
 
P

Phil_Harvey

You do have to remember that sometimes the idea and the concept may
need to override the standard use system. I am trying to implement an
idea.

You help has been useful, but you need not be so pedantic.

Thanks though
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,999
Latest member
MakersCBDGummiesReview

Latest Threads

Top