Don't like this style? Click here to change it! blue.css
I wasn't going to find a nice theme to tie them together… But to build your blog you'll need just a couple more tools.
It should be noted that design patterns are not recipes nor are they blueprints. Almost every single problem you have to code or solve is unique. We are creators of the world. Design patterns are practical ideas that have proved helpful for some situations. There are no silver bullets and no one can relieve you of your responsibility.
So the right way to approach these things is almost like a case study. What worked in Detroit might not work in Tampa but parts of it might. Never follow these things blindly but learn what they have to show you then synthesize your project using those notions.
So a single page app is a modern web design pattern. The idea is to give a fluid interesting multi-page web
experience while never reloading the page (or all of the expensive resources, images, libraries,
etc). Your blog engine will have several pages, the default way to do that is to make multiple
*.html
files and have them link to each other. Each triggering a complete reload of your assets.
When the MVC frameworks started to come out the main benefit wasn't MVC it was faster load times because of implementing the "single page app" pattern.
We'll break this down into three ideas that build to let you fake a page change:
Instead of a separate file per page we use a function to draw our new page.
All animation engines will wipe the screen and redraw it at least 20 times per second. We can use the same notion, clear the body or hide a div, now draw an appropriate page.
These simple exercises are intended to awaken the idea of a page as a user's experience and not a concrete file or chunk of text somewhere.
Rendering Pages Task 1: Create a webpage which begins by displaying the number 1.
Then every 3 seconds re-renders to show the next largest number. (Check out setTimeout if you haven't
already.
) Each of these renderings is a "separate page" if you want to see them that way. (What if the number was just
inside of a span
inside a long paragraph? See, it's a philosophical distinction.)
Modular Programmatic Page Task 2: Now create a page which has an input box of type text and a
button. When the button is clicked you should receive the value of the input box and if that value has length more than
0 call a function called greetingPage(name)
where name
is the input box's value. That function should wipe the screen, and add a
paragraph which has a greeting for name
.
Generate Back Action Task 3: Now adapt your greetingPage
function to
also generate a button which says change name
. But an event listener on that button which returns the
state of the screen to the original HTML. (Note you might have to go back and store the
document.body.innerHTML
depending on how you structured your first page.)
Here are some tricks for having unrendered HTML that you can keep up your sleeve for later.
Trick 1: multiple pages, all but one hidden.
See the Pen dGKyjZ by Andy Novocin (@AndyNovo) on CodePen.
Simple Pages Task 4: Add a fourth page template. Add a button on your page that when clicked alerts "hi".
Trick 2: multiple pages, all hidden, one display area.
See the Pen xZzxyq by Andy Novocin (@AndyNovo) on CodePen.
Simple Pages Task 5: Add a fourth to this example. What are the differences with the first trick. Any pros and cons that you can see?
Trick 3: script tags with bad types don't render.
See the Pen MKXWLa by Andy Novocin (@AndyNovo) on CodePen.
Simple Pages Task 6: Add a fourth. What are the differences? What are the pros and cons?
For what it's worth, the 3rd trick is the one I see most often in simple page examples. Another trick is to keep separate HTML template files and use a library to help you load them.
So in each of those above examples we see "Andy Rulz" (so very true) every time we load the page. But if this
were a normal website we could just send someone to blah.com/page2.html
if we wanted them to see
page2. Therefore the next dimension of this pattern is to have your code route a user to wherever they want to go.
(An alternative, more abstract and powerful, perspective is to treat urls as variables and react to them however we want.)
This is hard to do in a client-side app because I can't trick the browser into acting like a server with just one
file. So the first idea to take hold was using the hashchange
event.
When you add a #blahblahblah
to the end of a URL and hit enter the page does not refresh and an event
is fired. That's good enough for us! (some docs here
)
Here is the source code of css.prof.ninja/class15/sample.html which uses the
hashchange
listener to redraw the page.
Find and Fix Task 7: So launch your own page using that source on cloud9 (I want the URL this time). Navigate through by clicking the links. Now use your browser's back button. (You can turn off the alert if its too bothersome.) What is the flaw with the back button experience? Fix it.
A second flaw in that snippet is that sample.html#p2 doesn't send me to page 2 when clicked as a link.
We can fix that by triggering the hash "routing" (choosing what to render based on location.hash
) at
the load
event.
Check it out live at route.html#p3
Variable URLs Task 8: Note that when you head to variable.html#23/45/67 the location.hash
string
has a lot of data in it. I also used a hack to fetch the correct page id. Fix this by taking in the three hashed
numbers and displaying a page with those interpreted as x,y,z
coordinates. (Just parse the string to
turn those into variables.)
Baby Minecraft v0.1 Task 9: OK this is just because it sounds fun and we can do it now. Create a page with six buttons a north, south, east, west, and up and down (altitude). Take in x,y,z coordinates in the hash part of your URL. Wire the buttons so that they navigate the URL appropriately (clicking north takes you to the page but with the y coordinate increased by one, etc.).
Baby Minecraft v0.2 Task 10: Use one of these seedable random functions to create a
repeatable random number generator. At each new 'screen' use x*y + x*z + z*y
as your seed (or
whatever). Generate a scene based on that random number. Now explore the world you built.
I don't anticipate that we'll have enough time for this and Baby Minecraft sounds cool to me. So I'll give you my hand-crafted sample code and some insights for your own perusal:
See the Pen Small pushState Example by Andy Novocin (@AndyNovo) on CodePen.
The magic parts of that are history.pushState
and the popstate
event. The upshot is
that with pushState
we can change the URL and store a JSON of data for the new page. Then whenever
the user navigates forward and backward the popstate
event is fired and we get the JSON object back.
The real pro-use of this is to have pretty URLs that you want to send your user to rather than the ugly hash URLs. You can render a page in the fastest way but have the URL reflect a universal way ot that page. You can also alter the path of browser history (so the back/forward buttons have your goals not reality). You can even mix the hash and pushState methods by having your page interpret the hash into a pretty URL on page load.
I know this doesn't capture too much insight so here are several resources:
Here are some things I want you to think about this weekend:
Keep your truth out of the DOM
Here is a fundamental task for you to master (think about, think about strategies, compare and contrast the solutions):
Some folks aren't very comfortable creating repos from their work. Here are some instructions for creating a repo from your cloud9
workspaces. Practice my making three separate repos from scratch. Play with the git
documentation and learn something you didn't know to increase the likelihood that you will use version control in
your future projects. It also helps build your reputation and brand.
We will talk about this more next week but you can store your blog posts or user choices using the HTML localStorage options. https://www.w3.org/TR/webstorage/#dom-localstorage
I didn't say what my design choices would be for the build-a-bear and didn't have time to build one for you. So
what I imagined was an abstract interface (agreement really) for all of the attributes of a toy with each attribute having a
type, cost, description
. Each type
of attribute could be associated with a capacity of
those attributes (uniques have capacity 1). The toy could then have a generic add attribute which tosses it into
an array stored for that type
and if at capacity a remove attribute would trigger for the first
attribute in the array. The cost of the toy would be incremented. When the toy needs to describe itself it would
pass through it's attributes concatenating descriptions.