Pigs' houses (string arguments)

The story so far

In the last lesson, we looked at function parameters. Parameters let you reuse a function for different purposes. Check this out:

<button onclick="BetterPiggyBank.addCoin(0.01)" ...
<button onclick="BetterPiggyBank.addCoin(0.05)" ...
<button onclick="BetterPiggyBank.addCoin(0.10)" ...
<button onclick="BetterPiggyBank.addCoin(0.25)" ...

They all call the same function:

BetterPiggyBank.addCoin = function(amount) {
  //Do something with amount.
}

Arguments can be strings

amount is a number. So…

<button onclick="BetterPiggyBank.addCoin(0.25)" ...

… sends a number into addCoin().

You can send strings as well. That's what this lesson is about.

Requirements

A big bad wolf is attacking pigs' houses. Write an app that tracks the attacks, and the results. You can try it.

It starts like this:

Start

Click a button, and the app works out what happened, and adds the results to the output. For example:

Output

After another attack:

More output

The output area is invisible when the app starts. It shows after the first attack.

String arguments

We want a function we can call like this:

PigsHouse.blow = function(houseType) {

houseType is a string argument: "straw", "sticks", or "bricks".

Here's the code for the buttons that call the function:

<button onclick="PigsHouse.blow('straw')"...
<button onclick="PigsHouse.blow('sticks')"...
<button onclick="PigsHouse.blow('bricks')"...

We can pass a string argument just fine, but we have to be a little tricky with the quotes. The onclick uses double quotes:

onclick="..."

Inside the double quotes, use single quotes to give the argument:

PigsHouse.blow('straw')

Put them together:

onclick="PigsHouse.blow('straw')"

That's how you pass string arguments: use single quotes for the argument's value, inside double quotes for the onclick.

Adela
Adela
Could you switch the quotes? Use doubles inside singles?

Yes, you could.

<button onclick='PigsHouse.blow("straw")'...

Use whatever looks good to you.

Function code

Here's the code for the button. There are two parts.

  • Work out what happened for this attack.
  • Add that to the history of everything that happened.

  1. PigsHouse.blow = function(houseType) {
  2.     //Compute what happened for the attack.
  3.     var result = "<p>The wolf attacked a house made of " + houseType + ".</p>";
  4.     if ( houseType == 'straw' || houseType == 'sticks' ) {
  5.         result += "<p>House destroyed! Pig homeless!</p>";
  6.     }
  7.     else {
  8.         result += "<p>House still stands! Woohoo!</p>";
  9.     }
  10.     //Add this attack's results to the overall results.
  11.     allResults += result;
  12.     //Show all results.
  13.     $("#result").html(allResults);
  14.     $("#result-container").show();
  15. };
The code uses the accumulate HTML pattern.

Pattern

Accumulate HTML

Situation:
Some HTML will get longer and longer as things happen on the page.
Actions:
When something relevant happens, append HTML to a variable. Inject the variable into the page.

Let's look at the first part:

  • Work out what happened for this attack. DO THIS
  • Add that to the history of everything that happened.

One attack

Lines 3 to 9 work out what happened for the attack. Here's the screen shot for one attack.

Output for one attack

There are two pieces:

  • A summary of the attack ("The wolf attacked…").
  • The attack's effect ("House still…").

Here's the code that computes that output:

  1. var result = "<p>The wolf attacked a house made of " + houseType + ".</p>";
  2. if ( houseType == 'straw' || houseType == 'sticks' ) {
  3.     result += "<p>House destroyed! Pig homeless!</p>";
  4. }
  5. else {
  6.     result += "<p>House still stands! Woohoo!</p>";
  7. }
Line 3 creates a variable, result, to hold the output for the attack. It puts the first part of the output in the variable: what the wolf did.

Line 4 tests to see if the house was straw or sticks. That's what || means: or. If the house was straw or sticks, the code adds the destroyed message.

Line 8 adds the message for bricks.

Georgina
Georgina
The code doesn't validate houseType. What if it's empty? Or "plastic" or something?

Good point! The house type isn't entered by the user. It's in the code, like 'straw' here:

onclick="PigsHouse.blow('straw')"

We assume that the code is correct. An industrial-strength app would check that houseType is correct, but we're keeping things simple.

Ray
Ray
Other programs we've seen has used <br> tags to separate lines of output. This one uses <p> tags:

var result = "<p>The wolf attacked a house made of " + houseType + ".</p>";
    ...
    result += "<p>House destroyed! Pig homeless!</p>";

That's OK?

Yes. You can accumulate any HTML tags you want. No limits.

Here's the pseudocode again:

  • Work out what happened for this attack. DONE THIS
    • A summary of the attack ("The wolf attacked…").
    • The attack's effect ("House still…").
  • Add that to the history of everything that happened. NOW DO THIS

Marcus
Marcus
I get confused. We have two things, and the first of them has two things inside it.

I understand, but I lose track easily.

I hear you. It's easy to get confused. It happens to me, too.

Let's go back a bit. Maybe you start like this:

  • Work out what happened for this attack. DO THIS
  • Add that to the history of everything that happened.

So you start on the first thing. Now this might sound strange: when you're working on the first thing, ignore all of the other things. Just think about the first thing.

It's easy to get confused, if you try to keep everything in your head at once. So, don't try to keep everything in your head at once. How do you do that? Make a plan. That's what the pseudocode is. Work through the plan, one step at a time. Think only about the step you are working on.

Georgina
Georgina
That pseudocode plan is really important then. So is keeping track of which step in the plan you're working on.
Yes! Otherwise, you brain will get overloaded.

OK, so you're here:

  • Work out what happened for this attack. DO THIS
  • Add that to the history of everything that happened.

Then you work on the deets of the first step:

  • Work out what happened for this attack. DOING THIS
    • A summary of the attack ("The wolf attacked…").
    • The attack's effect ("House still…").
  • Add that to the history of everything that happened.

Then you write the code for the first thing in the first step, ignoring everything else:

  • Work out what happened for this attack.
    • A summary of the attack ("The wolf attacked…"). DOING THIS. IGNORE THE REST.
    • The attack's effect ("House still…").
  • Add that to the history of everything that happened.

Ray
Ray
Oh, I get it! You're working inside the first big step. It's like a brain bubble. You ignore everything that's outside the bubble.

Brain bubble

Right! That's how your brain can cope with the complexity.

Variables link the bubbles together. How does "A summary of the attack" know what the attack was? It looks in houseType.

Then you write the code for the next thing, ignoring everything else:

  • Work out what happened for this attack.
    • A summary of the attack ("The wolf attacked…").
    • The attack's effect ("House still…"). DOING THIS. IGNORE THE REST.
  • Add that to the history of everything that happened.

Once you're done that, you've finished the first step. You can go back outside the first big step's bubble, and start on the second step.

  • Work out what happened for this attack.
  • Add that to the history of everything that happened. DOING THIS. IGNORE THE REST.

Georgina
Georgina
Now you think inside the second step's bubble.
Exactly!

Adela
Adela
This makes sense.

But is it how real programmers work?

Definitely.

Many programmers start by putting the pseudocode in comments. Like this:

PigsHouse.blow = function(houseType) {
    //Compute what happened for the attack.
    //Add this attack's results to the overall results.
};

This matches the pseudocode:

  • Work out what happened for this attack.
  • Add that to the history of everything that happened.

Then they work on the deets for the first step. Maybe add more comments. Here's the pseudocode:

  • Work out what happened for this attack.
    • A summary of the attack ("The wolf attacked…").
    • The attack's effect ("House still…").
  • Add that to the history of everything that happened.

Here are the comments. The wording is different, but they mean the same thing.

PigsHouse.blow = function(houseType) {
    //Compute what happened for the attack.
    //Attack summary.
    //Attack result.
    //Add this attack's results to the overall results.
};

Start adding executable code:

PigsHouse.blow = function(houseType) {
    //Compute what happened for the attack.
    //Attack summary.
    var result = "<p>The wolf attacked a house made of " + houseType + ".</p>";
    //Attack result.
    //Add this attack's results to the overall results.
};
Marcus
Marcus
OK. I'm starting to see how this works. I'll have to try it, though.

We haven't heard from Anderson in a while.

Hey, Anderson. How's it going?

Anderson
Anderson
Huh? What?
You're skimming again?

Anderson
Anderson
Yeah. Start with an exercise, and skim back, until you find code to copy-and-paste. It's the smart thing to do.

Reading is for losers.

Ray
Ray
Dude, you're missing all the advice on how to make things easier on your brain. And how the code works.

Anderson
Anderson
I'm just being efficient. I work, you know. Pizzas don't make themselves.

Anyway, this course sucks. It's too hard. All this coding makes me frustrated, and angry.

Georgina
Georgina
Hmmm… I wonder why you're frustrated? What a mystery.
Marcus
Marcus
Who knows why Anderson is frustrated? I can't figure it out.
Ray
Ray
Me neither. There's no reason he should frustrated.

Wait… could it be that skimming doesn't work?

No, that couldn't be it. Looks like we'll never know.

OK, let's go back to the last big step:

  • Work out what happened for this attack.
  • Add that to the history of everything that happened. DOING THIS

Adding to the history

PigsHouse.blow = function(houseType) {
    //Compute what happened for the attack.
    ...
    //Add this attack's results to the overall results.
    allResults += result;
    //Show all results.
    $("#result").html(allResults);
    $("#result-container").show();
};

allResults is declared at the top of the JS code:

<script>
    "use strict";
    var PigsHouse = PigsHouse || {};
    (function($) {
        //History of everything that happened.
        var allResults = "";

This line…

allResults += result;

… appends the result of the current attack.

Now to show it. Here's the HTML for the output region.

<div id="result-container" class="hide-on-load">
    <h3>Result</h3>
    <div id="result"></div>
</div>

The JS injects allResults, and shows the container.

$("#result").html(allResults);
$("#result-container").show();

Adela
Adela
The hide-on-load means that the container doesn't show when the page loads.

The show() means that the container appears, when there is something to show.

Right! Exactly.

We're done. You can try it. Press Ctrl+U to look at the code. Press F12 to open the dev tools, and mess around.

Summary

You can pass string arguments to functions.