WebFund 2015W Lecture 10: Difference between revisions

From Soma-notes
 
(3 intermediate revisions by 2 users not shown)
Line 6: Line 6:


The video from the lecture given on February 4, 2015 is available now [http://homeostasis.scs.carleton.ca/~soma/webfund-2015w/lectures/comp2406-2015w-lec10-04Feb2015.mp4 as an MP4].
The video from the lecture given on February 4, 2015 is available now [http://homeostasis.scs.carleton.ca/~soma/webfund-2015w/lectures/comp2406-2015w-lec10-04Feb2015.mp4 as an MP4].


==Notes==
==Notes==
Line 22: Line 23:


<pre>
<pre>
   if (!userNotes.hasOwnProperty(username)) {
   if (!Object.hasOwnProperty.apply(userNotes, [username])) {
       userNotes[username] = [];
       userNotes[username] = [];
   }
   }
Line 36: Line 37:


Thus, use hasOwnProperty()!
Thus, use hasOwnProperty()!
<h3>Breaking a few things in notes-demo</h3>
In app.js, remove <code>var app = express();</code>
<ul>
  <li>If you delete this line, app is going to be undefined.</li>
  <li>This becomes a problem because you’d be trying to access parts of an undefined
object.</li>
  <li>You get a reference error when doing this.</li>
</ul>
In app.js, remove <code>var session = require('express-session');</code>
<ul>
  <li>If this line is deleted you get an error: session is not defined.</li>
  <li>This error comes from the calls in index.js to get the username (<code>req.session.username</code>).</li>
  <li>Since the session module is not loaded, this code cannot execute correctly.</li>
</ul>
In index.js, inside the <code>router.get('/', ...)</code> function, remove <code>error: req.query.error</code>
<ul>
  <li>This causes problems when the user tries to access pages which require them to be logged in such as /notes and /edit.</li>
  <li>The 'not logged in' error will still show up in the URL but not display the error message on the page itself anymore.</li>
</ul>
<h3>JavaScript in Jade</h3>
In index.jade, does the <code>-if(error)</code> get seen by the browser?
No: take a look at the page source and you will see that there is only the div tag and not the condition.
You must realize:
<ul>
  <li>When you add any JavaScript into the body of a jade template, it is executed on the server (server side JavaScript) and is not seen by the web browser.</li>
  <li>This idea applies to all JavaScript (that is not contained in a script tag).</li>
  <li>The web browser just gets the result.</li>
</ul>
<h4>Making a pop up box when the web page is loaded</h4>
<ul>
  <li>The <code>res.render()</code> calls render a Jade template and and then send them to the browser as an HTML page.</li>
  <li>It is inside these Jade templates that code can be added to ensure that JavaScript code is sent along with the HTML to be executed on the client-side.</li>
  <li>Add in a <code>block header</code> into index.jade.
<code><pre>
block header
  script alert(“Hi there”)
</pre></code>
  </li>
  <li>Most of the time you want to put your JavaScript in a separate file (in the public/
JavaScripts folder) so instead you can do the following:
    <ul>
      <li>In public/JavaScripts create a file called alert.js with contents: <code>alert(“Hello there again”);</code></li>
      <li>Change the code in index.jade to be:
<code><pre>
block header
  script(src="javascripts/alert.js")
</pre></code>
      </li>
    </ul>
  </li>
  <li>If we want this script to also be able to run in a terminal, it must be modified.</li>
  <li>We need to check if alert is defined (as it is not defined in a regular terminal running Node) to determine whether or not we are in the browser and have access to the <code>alert()</code> function.</li>
  <li>If there are no alert boxes, we must display to the console instead.
<code><pre>
if (typeof(alert)==="undefined") {
  myalert = function(s) {
      console.log(s); // this will output to the console instead of pop up in browser
  }
}
for(i=0; i<5; i++) {
  alert(“Hello there again”);
}
</pre></code>
  </li>
  <li><code>typeof()</code> is a useful function
    <ul>
      <li><code>typeof(5)</code> gives you ‘number’.</li>
      <li><code>typeof(“hello”)</code> gives you ‘string’.</li>
      <li><code>typeof(foo)</code> gives you ‘undefined’.</li>
      <li>You have to remember that it returns a string.</li>
    </ul>
  </li>
  <li>When trying to read the source code for scripts on other pages, some are very hard to read.</li>
  <li>Any idea why the code from Google might be really hard to read?
    <ul>
      <li>The JavaScript inside of a page is what powers advertisements.</li>
      <li>If you can figure out the JavaScript you can engineer fake clicks.</li>
      <li>Google obscures the JavaScript to prevent click fraud.</li>
    </ul>
  </li>
</ul>
<h3>Why do you get an error when you try to log in with ‘hasOwnProperty’?</h3>
<ul>
  <li>In the <code>router.post('/login',...)</code> function in index.js, we check for the username in userNotes.</li>
  <li>The fact that the userNotes object has a function called <code>hasOwnProperty</code> is causing a problem.</li>
  <li>We can see that this is an inherited function through the following code example:
<code><pre>
> x = {}
{}
> x.hasOwnProperty()
[Function: hasOwnProperty]
> y = Object.create(null);
{}
> y
{}
> y.hasOwnProperty()
undefined
</pre></code>
  </li>
</ul>
<h3>Adding tags in notes-demo</h3>
<ul>
  <li>We want another field for the notes to hold tags (information about the notes).</li>
  <li>Add a field to display tags in notes.jade: <code>i= userNotes[i].tags</code></li>
  <li>Appropriate tag data must be added for Alice in the data structure in index.js to view the change.</li>
  <li>Why didn't we have to pass the tags directly to the jade file?
    <ul>
      <li>Because we just passed in the whole notes object, in this case its called userNotes.</li>
      <li>Since the entire object is passed in, the tags get passed in with it.</li>
      <li>If “tags” was a separate data structure, it would need to be added to index.js to be
passed in also.</li>
    </ul>
  </li>
  <li>To be able to edit the tags we need to go to edit.jade and add
<code><pre>
div
  input#title(type=”text”, name=”tags”, value=note.tags)
</pre></code>
  </li>
  <li>To make sure there is a default tag when we create a new note we look at the <code>router.get('/new', ...</code> function in index.js and add an additional attribute to the notes object: <code>tags: “Add tags here”</code></li>
  <li>But we also need to make sure the tag field actually gets the value when you create
a new note or update one. In index.js, in the <code>router.post('/update', ...</code> function we also need to add in: <code>note.tags = req.body.tags</code></li>
</ul>
<h3>Adding jQuery to a page</h3>
<ul>
  <li>In the header of a Jade file, link the script using <code>script(src="...")</code><li>
  <li>You would either have to download the jQuery file to your web app and put it in the
JavaScripts directory or you could make the src a full URL and link it from another
place on the web, ex:
<br>
<code><pre>
<script src=”//code.jquery.com/jquery-1.11.2.min.js”></script>
<script src=”//code.jquery.com/jquery-migrate-1.2.1.min.js></script>
</pre></code>
  </li>
  <li>Why would it be better to use the longer URL?
    <ul>
      <li>It saves bandwidth on your server because you don’t have to serve the file; another website does.</li>
      <li>Users may already have the file cached from other websites so it can save bandwidth for them as well.</li>
    </ul>
  </li>
</ul>

Latest revision as of 17:14, 9 February 2015

Resources


Video

The video from the lecture given on February 4, 2015 is available now as an MP4.


Notes

CORRECTION regarding hasOwnProperty()

In lecture we saw that we could break notes-demo by giving hasOwnProperty as a username. This error is because the following code in the login post handler is incorrect:

    if (!userNotes[username]) {
	userNotes[username] = [];
    }

This code should instead say:

   if (!Object.hasOwnProperty.apply(userNotes, [username])) {
       userNotes[username] = [];
   }

If you are treating a JavaScript object as an associative array you must explicitly check whether a given key value (property) is present using the hasOwnProperty() method inherited by every object.

Note you can create an object x with no prototype by doing the following:

  x = Object.create(null);

However, this is not normally done. Indeed, even if you use a JSON parser objects will have a non-null prototype.

Thus, use hasOwnProperty()!


Breaking a few things in notes-demo

In app.js, remove var app = express();

  • If you delete this line, app is going to be undefined.
  • This becomes a problem because you’d be trying to access parts of an undefined object.
  • You get a reference error when doing this.

In app.js, remove var session = require('express-session');

  • If this line is deleted you get an error: session is not defined.
  • This error comes from the calls in index.js to get the username (req.session.username).
  • Since the session module is not loaded, this code cannot execute correctly.

In index.js, inside the router.get('/', ...) function, remove error: req.query.error

  • This causes problems when the user tries to access pages which require them to be logged in such as /notes and /edit.
  • The 'not logged in' error will still show up in the URL but not display the error message on the page itself anymore.

JavaScript in Jade

In index.jade, does the -if(error) get seen by the browser?

No: take a look at the page source and you will see that there is only the div tag and not the condition.

You must realize:

  • When you add any JavaScript into the body of a jade template, it is executed on the server (server side JavaScript) and is not seen by the web browser.
  • This idea applies to all JavaScript (that is not contained in a script tag).
  • The web browser just gets the result.

Making a pop up box when the web page is loaded

  • The res.render() calls render a Jade template and and then send them to the browser as an HTML page.
  • It is inside these Jade templates that code can be added to ensure that JavaScript code is sent along with the HTML to be executed on the client-side.
  • Add in a block header into index.jade.
    block header
      script alert(“Hi there”)
    
  • Most of the time you want to put your JavaScript in a separate file (in the public/ JavaScripts folder) so instead you can do the following:
    • In public/JavaScripts create a file called alert.js with contents: alert(“Hello there again”);
    • Change the code in index.jade to be:
      block header
        script(src="javascripts/alert.js")
      
  • If we want this script to also be able to run in a terminal, it must be modified.
  • We need to check if alert is defined (as it is not defined in a regular terminal running Node) to determine whether or not we are in the browser and have access to the alert() function.
  • If there are no alert boxes, we must display to the console instead.
    if (typeof(alert)==="undefined") {
       myalert = function(s) {
          console.log(s); // this will output to the console instead of pop up in browser
       }
    }
    
    for(i=0; i<5; i++) {
       alert(“Hello there again”);
    }
    
  • typeof() is a useful function
    • typeof(5) gives you ‘number’.
    • typeof(“hello”) gives you ‘string’.
    • typeof(foo) gives you ‘undefined’.
    • You have to remember that it returns a string.
  • When trying to read the source code for scripts on other pages, some are very hard to read.
  • Any idea why the code from Google might be really hard to read?
    • The JavaScript inside of a page is what powers advertisements.
    • If you can figure out the JavaScript you can engineer fake clicks.
    • Google obscures the JavaScript to prevent click fraud.

Why do you get an error when you try to log in with ‘hasOwnProperty’?

  • In the router.post('/login',...) function in index.js, we check for the username in userNotes.
  • The fact that the userNotes object has a function called hasOwnProperty is causing a problem.
  • We can see that this is an inherited function through the following code example:
    > x = {}
    {}
    > x.hasOwnProperty()
    [Function: hasOwnProperty]
    > y = Object.create(null);
    {}
    > y
    {}
    > y.hasOwnProperty()
    undefined
    

Adding tags in notes-demo

  • We want another field for the notes to hold tags (information about the notes).
  • Add a field to display tags in notes.jade: i= userNotes[i].tags
  • Appropriate tag data must be added for Alice in the data structure in index.js to view the change.
  • Why didn't we have to pass the tags directly to the jade file?
    • Because we just passed in the whole notes object, in this case its called userNotes.
    • Since the entire object is passed in, the tags get passed in with it.
    • If “tags” was a separate data structure, it would need to be added to index.js to be passed in also.
  • To be able to edit the tags we need to go to edit.jade and add
    div
      input#title(type=”text”, name=”tags”, value=note.tags)
    
  • To make sure there is a default tag when we create a new note we look at the router.get('/new', ... function in index.js and add an additional attribute to the notes object: tags: “Add tags here”
  • But we also need to make sure the tag field actually gets the value when you create a new note or update one. In index.js, in the router.post('/update', ... function we also need to add in: note.tags = req.body.tags

Adding jQuery to a page

  • In the header of a Jade file, link the script using script(src="...")
  • You would either have to download the jQuery file to your web app and put it in the JavaScripts directory or you could make the src a full URL and link it from another place on the web, ex:
    <script src=”//code.jquery.com/jquery-1.11.2.min.js”></script>
    <script src=”//code.jquery.com/jquery-migrate-1.2.1.min.js></script>
    
  • Why would it be better to use the longer URL?
    • It saves bandwidth on your server because you don’t have to serve the file; another website does.
    • Users may already have the file cached from other websites so it can save bandwidth for them as well.