CICS 515 a Internet Programming Week 4 Mike Feeley JavaScript - - PowerPoint PPT Presentation

cics 515 a internet programming week 4 mike feeley
SMART_READER_LITE
LIVE PREVIEW

CICS 515 a Internet Programming Week 4 Mike Feeley JavaScript - - PowerPoint PPT Presentation

CICS 515 a Internet Programming Week 4 Mike Feeley JavaScript continued ... Validators JavaScript to check validity of user input report errors to user without going to server so that user can fix them quickly and easily


slide-1
SLIDE 1

CICS 515 a Internet Programming Week 4 Mike Feeley

slide-2
SLIDE 2

JavaScript continued ...

slide-3
SLIDE 3

Validators

JavaScript to check validity of user input

  • report errors to user without going to server
  • so that user can fix them quickly and easily

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/validator/foo.html

  • lets say that first field can only have value ‘zero’ and second ‘one’
  • connect JavaScript event handler to input’s onblur event (or maybe onchange)

<html> <head> </head> <body onload='whenLoaded()'> <form onsubmit='javascript: return this.isSubmitOkay ()'> <table> <tr> <td><input type='text' size='20' onblur='validate()'></td> </tr> <tr> <td><input type='text' size='20' onblur='validate()'></td> </tr> </table> <input type='submit' value='submit'> </form> </body> </html>

slide-4
SLIDE 4

giving error feedback to user

  • immediate responsiveness, don’t wait for submit to indicate errors
  • “modal” (fix error before continuing) or not (allow multiple inputs before fixing errors)
  • clearly indicate fields in error and what is wrong
  • consistent across fields, forms and pages

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/foo.html pick standard for assigning field IDs

  • x_eFlag is the element that is highlighted when there’s an error in input x
  • x_eMsg is the element where error message is displayed

use style sheet for highlighting

<td id='i0_eFlag'><input id='i0' type='text' size='20' onblur='validate()'></td> <td id='i0_eMsg' class='ErrorMessage'></td> <td id='i1_eFlag'><input id='i1' type='text' size='20' onblur='validate()'></td> <td id='i1_eMsg' class='ErrorMessage'></td> *.InputError { background-color: red; } *.InputOkay { background-color: white; }

slide-5
SLIDE 5

JavaScript to set/clear an error on a field but, we’ll do it in object-oriented fashion

  • extend the DOM Input object to add these new properties

var ERROR_FLAG_SUFFIX = '_eFlag'; var ERROR_MSG_SUFFIX = '_eMsg'; function setError () { document.getElementById(this.eFlagID()).className = INPUT_ERROR_CLASS; document.getElementById(this.eMsgID()).innerHTML = this.errMsg; } function clearError () { document.getElementById(this.eFlagID()).className = INPUT_OKAY_CLASS; document.getElementById(this.eMsgID()).innerHTML = ''; }

setError () highlights field and sets its error message clearError () unhilights field and clears its error message validate () calld by onblur event to check field’s validity isValid () returns true if and only if current value of field is valid errMsg error message to display if field is in error hasError true if and only if current value of field is invalid

slide-6
SLIDE 6

extending the Input prototype in JavaScript set isValid and errMsg for inputs in page’s onload hander

HTMLInputElement.prototype.setError = function () { this.hasError = true; document.getElementById(this.eFlagID()).className = INPUT_ERROR_CLASS; document.getElementById(this.eMsgID()).innerHTML = this.errMsg; this.form.disableSubmit (true); } HTMLInputElement.prototype.clearError = function () { this.hasError = false; document.getElementById(this.eFlagID()).className = INPUT_OKAY_CLASS; document.getElementById(this.eMsgID()).innerHTML = ''; if (this.form.isSubmitOkay()) this.form.disableSubmit (false); } HTMLInputElement.prototype.validate = function () { if (this.isValid ()) this.clearError (); else this.setError (); } function whenLoaded () { document.getElementById('i0').isValid = function () { return this.value=='zero'; }; document.getElementById('i0').errMsg = 'must be "zero"'; document.getElementById('i1').isValid = function () { return this.value=='one'; }; document.getElementById('i1').errMsg = 'must be "one"'; }

slide-7
SLIDE 7

disable submitting if there is an error

HTMLFormElement.prototype.disableSubmit = function (disable) { for (var i=0; i<this.elements.length; i++) if (this.elements[i].type=='submit') this.elements[i].disabled=disable; } HTMLFormElement.prototype.isSubmitOkay = function () { for (var i=0; i<this.elements.length; i++) if (this.elements[i].hasError) return false; return true; } <body onload='whenLoaded()'> <form onsubmit='javascript: return this.isSubmitOkay ()'>

slide-8
SLIDE 8

Putting it all together

<html> <head> <link href='Project.css' rel='stylesheet' type='text/css'> <script src='ValidateInput.js' language='JavaScript' ></script> <script type='text/JavaScript'> function whenLoaded () { document.getElementById('i0').isValid = function () { return this.value=='zero'; }; document.getElementById('i0').errMsg = 'must be "zero"'; document.getElementById('i1').isValid = function () { return this.value=='one'; }; document.getElementById('i1').errMsg = 'must be "one"'; } </script> </head> <body onload='whenLoaded()'> <form onsubmit='javascript: return this.isSubmitOkay ()'> <table> <tr> <td id='i0_eFlag'><input id='i0' type='text' size='20'

  • nblur='validate()'></td>

<td id='i0_eMsg' class='ErrorMessage'></td> </tr> <tr> <td id='i1_eFlag'><input id='i1' type='text' size='20'

  • nblur='validate()'></td>

<td id='i1_eMsg' class='ErrorMessage'></td> </tr> </table> <input type='submit' value='submit'> </form> </body> </html>

slide-9
SLIDE 9

var INPUT_ERROR_CLASS = 'InputError'; var INPUT_OKAY_CLASS = 'InputOkay'; var ERROR_FLAG_SUFFIX = '_eFlag'; var ERROR_MSG_SUFFIX = '_eMsg'; HTMLFormElement.prototype.disableSubmit = function (disable) { for (var i=0; i<this.elements.length; i++) if (this.elements[i].type=='submit') this.elements[i].disabled=disable; } HTMLFormElement.prototype.isSubmitOkay = function () { for (var i=0; i<this.elements.length; i++) if (this.elements[i].hasError) return false; return true; } HTMLInputElement.prototype.eFlagID = function () { return this.id+ERROR_FLAG_SUFFIX; } HTMLInputElement.prototype.eMsgID = function () { return this.id+ERROR_MSG_SUFFIX; } HTMLInputElement.prototype.setError = function () { this.hasError = true; document.getElementById(this.eFlagID()).className = INPUT_ERROR_CLASS; document.getElementById(this.eMsgID()).innerHTML = this.errMsg; this.form.disableSubmit (true); } HTMLInputElement.prototype.clearError = function () { this.hasError = false; document.getElementById(this.eFlagID()).className = INPUT_OKAY_CLASS; document.getElementById(this.eMsgID()).innerHTML = ''; if (this.form.isSubmitOkay()) this.form.disableSubmit (false); } HTMLInputElement.prototype.validate = function () { if (this.isValid ()) this.clearError (); else this.setError (); }

slide-10
SLIDE 10

Combining JavaScript with PHP and MySQL

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/enterStudents6.php

slide-11
SLIDE 11

add country to this form

  • assume country must be country in North America
  • not as a drop-down box, why?

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/enterStudents7.php

Your turn ...

slide-12
SLIDE 12

Checking for valid country

code

var isValidCountry = function () { return (!this.value || (this.value=='Canada' || this.value=='United States' || this.value=='Mexico')); }; var errMsgCountry = 'country in North America (property capitalized)'; echo "<script type='text/JavaScript'>\n"; echo "function loadCountryValidators () {\n"; for ($i=0; $i<mysql_numrows($rows); $i++) { echo "document.getElementById('country$i').isValid = isValidCountry;\n"; echo "document.getElementById('country$i').errMsg = errMsgCountry;\n"; } echo "}\n</script>\n"; echo "<td><table><tr><td id='country${i}_eFlag'> <input id='country$i' name='country[]' type='text' size='30’ value='$country' "; echo "onchange='checkBox($i)' onblur='validate()'></td></tr> <tr><td id='country${i}_eMsg' class='ErrorMessage'>&nbsp;</td></tr> </table>\n";

slide-13
SLIDE 13

separation of concerns is important

  • style elements in the style file
  • so that site can define a consistent look and feel and that it can be easily changed
  • form validation defined at the class level
  • so that every input field is validated in a consistent manner with minimal form-specific work
  • error flagging and message at least semi-independent from style and HTML

but what we have so far is not really good enough

  • the problem is that HTML still encodes some formatting (table, rows, cells etc.)
  • no connection to underlying data types in database
  • validation and formatting should be properties of the data’s schema
  • but how ...

Modular design in HTML / JavaScript

slide-14
SLIDE 14

XML

slide-15
SLIDE 15

extensible markup language

  • adds structure to a text document
  • HTML is an example
  • XML allows creation of new element tags and attributes

uses

  • describe database-stored values once extracted for exchange between databases
  • as a sort of database itself inside of a file (stuff like configuration parameters etc.)
  • as data transport between web servers and clients

how it is different from relational databases like SQL

  • any RDB table can be described in XML
  • key difference is that XML is recursive (allows nesting), while RDB is not

XML

<student> <sid>10</sid> <name>First Student</name> </student> <student> <sid>10</sid> <name>Second Student</name> </student> <blogEntry> <author>Feeley</author> <text>Blah Blah</text> <blogEntry> <author>Feeley</author> <text>More blather</text> </blogEntry> </blogEntry>

slide-16
SLIDE 16

XML syntax

element

  • an element is delimited by opening and closing tags
  • <foo> ... </foo> or <foo/>

attribute

  • an element can have attributes
  • <foo attribute=’blah’>

inner text

  • an element can have text enclosed by opening and closing tags
  • this text becomes the element’s nodeValue

nested subelements

  • an element can have other XML elements encodes by opening and closing tags
  • thus creating a tree of elements for the document
  • element types can be recursive, as we have seen, but element values are not

syntax checking is strict

  • tags are case sensitive, closing and proper nesting is required
slide-17
SLIDE 17

XML document tree

all XML documents must have a root element

  • earlier examples were not complete, they need roots like <students> and <blogEntrys>
  • I know that the plural of blogEntry is blogEntries, but you’ll see why I’ve chosen this style later

elements form tree text and attributes are child nodes of their element

<students> <student> <sid>10</sid> <name>First Student</name> </student> <student> <sid>20</sid> <name>Second Student</name> </student> </students> <blogEntrys> <blogEntry> <author>Feeley</author> <text>Blah Blah</text> <blogEntry> <author>Feeley</author> <text>More blather</text> </blogEntry> </blogEntry> </blogEntrys>

slide-18
SLIDE 18

An XML example

xml data description

<?xml version='1.0'?> <?xml-stylesheet type='text/xsl' href='students.xsl'?> <students> <student> <sid>10</sid> <name>First Student</name> <birthCountry>Canada</birthCountry> </student> <student> <sid>20</sid> <name>Second Student</name> <birthCountry>United States</birthCountry> </student> </students>

slide-19
SLIDE 19

XML Namespaces

a set of tag definitions is called a namespace XML documents can include tags from multiple namespaces

  • e.g., HTML is a XML document whose namespace is defined by www.w3.org

XML elements can specify a namespace using xmlns attribute documents with multiple namespaces use qualified tag names

  • xmlns attribute picks a qualifier for namespace
  • then tags for that namespace are proceeded by qualifier colon

folks have tried to devise namespaces for everything

  • this stuff is best ignored whenever possible

<html xmlns="http://www.w3.org/1999/xhtml"> <xsl:stylesheet version='1.0' xmlns:xsl = 'http://www.w3.org/1999/XSL/Transform'> <xsl:template match = '/'> ...

slide-20
SLIDE 20

XML style sheet (converts XML to HTML)

  • defined by an XML namespace called XSL/Transform
  • http://ws.cs.ubc.ca/~feeley/cics515/code/week4/students0/students.xsl

<?xml version='1.0'?> <xsl:stylesheet version='1.0' xmlns:xsl = 'http://www.w3.org/1999/XSL/Transform'> <xsl:template match = '/'> <html> <body> <table border='1'> <xsl:for-each select = 'students/student'> <tr> <td><xsl:value-of select='sid'/></td> <td><xsl:value-of select='name'/></td> <td><xsl:value-of select='country'/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>

Web browsers can display XML

slide-21
SLIDE 21

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/students0/students.xsl

<?xml version='1.0'?> <?xml-stylesheet type='text/xsl' href='students.xsl'?> <students xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='students.xsd'> <student> <sid>10</sid> <name>First Student</name> <country>Canada</country> </student> <student> <sid>20</sid> <name>Second Student</name> <country>United States</country> </student> </students>

slide-22
SLIDE 22

defines XML document type

  • documents permitted syntax of XML documents of a user-defined type
  • can be checked

schemas are optional

  • only really needed when transferring data between realms
  • within a single realm usually not necessary, though some form of documentation is

DTD

  • fairly easy to read, but not in XML and do not support namespaces

XML Schema

<!ELEMENT blogEntrys (blogEntry*)> <!ELEMENT blogEntry (name, entry+)> <!ELEMENT entry (date, author, text, entry+)> <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE blogs SYSTEM 'blog.dtd'> <blogs>

slide-23
SLIDE 23

<?xml version='1.0' encoding='utf-8'?> <xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'> <xsd:element name='blogEntry'> <xsd:complexType> <xsd:sequence> <xsd:element name='date'/> <xsd:element name='author' type='xsd:string'/> <xsd:element name='text'/> <xsd:element ref='blogEntry' minOccurs='0' maxOccurs='unbounded'/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name='blogEntries'> <xsd:complexType> <xsd:sequence minOccurs='0' maxOccurs='unbounded'> <xsd:element name='blogEntry'> <xsd:complexType> <xsd:sequence> <xsd:element name='name' type='xsd:string'/> <xsd:element ref='entry' minOccurs='0' maxOccurs='unbounded'/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>

XSD in XML format and impossible to read

slide-24
SLIDE 24

name schema in document http://www.w3.org/2001/03/webdata/xsv

  • if your xml and xsd files are have Internet-accessible URLs, select “show warnings”
  • otherwise you can upload your files to this web site have it will check them from there

http://www.ltg.ed.ac.uk/~ht/xsv-status.html

  • downloadable versions (easy for windows)

Validating XML to a Schema

<?xml version='1.0' encoding='utf-8'?> <blogEntrys xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='blog.xsd'> <blogEntry> <id></id> <date></date> <author>Mike</author> ...

slide-25
SLIDE 25

AJAX

slide-26
SLIDE 26

Asynchronous JavaScript with XML

server / client exchange

  • only data
  • formatted in XML

JavaScript

  • loads XML from server
  • uses DOM model for access XML
  • displays data using “Dynamic HTML”, creating HTML elements on the fly
  • sends updates back in similar way

the old way

  • client/server exchange was page at a time
  • server formatted data (e.g., into tables)
  • identity / type of data elements not know to JavaScript
slide-27
SLIDE 27

Talking to the server

create httpRequest object

  • IE and result of the world do it differently

function newXMLHttpRequest () { var xmlHttp; if (window.XMLHttpRequest) { // code for Mozilla, etc. xmlHttp=new XMLHttpRequest() } else if (window.ActiveXObject) { // code for IE xmlHttp=new ActiveXObject("Microsoft.XMLHTTP") } else throw 'Your browser does not support AJAX'; ...

slide-28
SLIDE 28

add method for getting some XML from server asynchonously

  • system calls method assigned to onreadystatechange four times
  • as processing of request proceeds: loading, loaded, interactive and complete (=4)
  • we call method provided in whenComplete when requests completes
  • call whenError if there is an error

function newXMLHttpRequest () { ... xmlHttp.whenStateChanges = function () { if (this.readyState==4) { if (this.status==200 && this.responseXML!=null) { if (this.whenComplete) this.whenComplete (this.responseXML); } else { if (this.whenError) this.whenError (); } } xmlHttp.loadXMLDoc = function (url, whenComplete, whenError) { this.whenComplete = whenComplete; this.whenError = whenError; this.onreadystatechange=this.whenStateChanges; this.open("GET",url,true); this.send(null); }; }

slide-29
SLIDE 29

making a call to the server

  • specify the URL (an xml file for now) and the “callback” method

function showStudentTable (xml) { // here when XML request completes } function xmlLoadError () { alert ('error loading xml'); } var xmlHttp = newXMLHttpRequest (); xmlHttp.loadXMLDoc ('students.xml',showStudentTable,xmlLoadError);

slide-30
SLIDE 30

showing the data in a table (with expand/collapse feature)

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/students1/showStudents0.html

function showStudentTable (xml) { var students = xml.getElementsByTagName('student'); document.write ('<table>'); for (i=0; i<students.length; i++) { document.write ('<tr>'); student = students[i].childNodes; for (j=0; j<student.length; j++) if (student[j].nodeType!=3) { if (student[j].nodeName=='sid') { document.write ('<td onclick="toggleExpand(',i,')">?</td>'); document.write ('<td>'+student[j].firstChild.nodeValue+'</td>'); } else { document.write ('<td name="t',i,'">'+ student[j].firstChild.nodeValue+'</td>'); } } document.write('</tr>'); } document.write ('</table>'); }

slide-31
SLIDE 31

create a new document element object

  • element = document.createElement (<element-name>)

add element somewhere using appendChild() method

  • document.body.appendChild (element);
  • anotherElement.appendChild (element);

working with DOM tables

  • table = document.createElement (‘table’);
  • document.body.appendChild (table);
  • row = table.insertRow (rowNum);
  • cell = row.insertCell (cellNum);
  • cell.appendChild (element);
  • cell.innerHTML = “blah blah”;

Creating web page with DOM objects

slide-32
SLIDE 32

use helper function to read XML createStudentTable using DOM

Improved example

function getValueByNodeName (nodeList, aNodeName) { for (var i=0; i<nodeList.length; i++) if (nodeList[i].nodeName==aNodeName) return nodeList[i].firstChild? nodeList[i].firstChild.nodeValue : ''; } function createStudentTable (xml) { var students = xml.getElementsByTagName('student'); var table = document.createElement('table'); document.body.appendChild(table); for (var rowNum=0; rowNum<students.length; rowNum++) buildStudentRow (table.insertRow(table.rows.length), students[rowNum].childNodes); }

slide-33
SLIDE 33

build student table using DOM

function buildStudentRow (row, student) { row.id = 'row'+row.rowIndex; var cell = row.insertCell (0); var expandButton = document.createElement('a'); expandButton.href = 'javascript: toggleVisibility ("'+row.id+'")'; expandButton.innerHTML = '>'; expandButton.className = 'expandButton'; cell.appendChild (expandButton); var cell = row.insertCell (1); innerTable = document.createElement ('table'); cell.appendChild (innerTable); row.summaryRow = innerTable.insertRow (0); row.summaryRow.style.display = 'block'; row.summaryRow.insertCell(0).innerHTML = getValueByNodeName (student,'sid'); row.summaryRow.insertCell(1).innerHTML = 'summary'; row.detailRow = innerTable.insertRow (1); row.detailRow.style.display = 'none'; row.detailRow.insertCell(0).innerHTML = getValueByNodeName (student,'sid'); row.detailRow.insertCell(1).innerHTML = getValueByNodeName (student,'name'); row.detailRow.insertCell(2).innerHTML = getValueByNodeName (student,'country'); }

slide-34
SLIDE 34

toggleVisibility some style

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/students1/showStudents1.html

function toggleVisibility (rowId) { row = document.getElementById (rowId); if (row.summaryRow.style.display == 'none') { row.summaryRow.style.display = ''; row.detailRow.style.display = 'none'; row.cells[0].firstChild.innerHTML = '>'; } else { row.summaryRow.style.display = 'none'; row.detailRow.style.display = ''; row.cells[0].firstChild.innerHTML = 'v'; } }

<style type='text/css'> a.StudentTable_ExpandButton { color: blue; text-decoration: none; font-family: arial; font-weight: bold; } *.StudentTable td { vertical-align: top; } *.StudentTable_Summary { margin-top: -4; color: grey; vertical-align: bottom; font-size: 14; font-style: italic; } *.StudentTable_Detail { background: #cccccc; vertical-align: top; } </style>

slide-35
SLIDE 35

http://ws.cs.ubc.ca/~feeley/cics515/code/week4/students2/showStudents.html

Creating XML from MySQL at server

<?php include 'dbconfig.php'; include 'opendb.php'; header ('Content-Type: text/xml'); $rows = mysql_query ("SELECT sid, name, birthCountry FROM student ORDER BY sid"); if ($rows) { $xml_output .= "<?xml version='1.0'?>\n"; $xml_output .= "<students>\n"; while ($row = mysql_fetch_assoc ($rows)) { $xml_output .= "<student>\n"; $xml_output .= "<sid>".$row['sid']."</sid>\n"; $xml_output .= "<name>".$row['name']."</name>\n"; $xml_output .= "<country>".$row['birthCountry']."</country>\n"; $xml_output .= "</student>\n"; } $xml_output .= "</students>\n"; } mysql_close (); echo $xml_output; ?> xmlHttp.loadXMLDoc ('selectAllStudents.php',createStudentTable,xmlLoadError);