JavaScript and Regex: Using a regular expression and .replace() to strip (foo) from a string

Here’s a quick tutorial on using regular expressions in JavaScript to edit a string and return the modified result. My strings looked like this:

"Toyota (1999 - 2005)"
"Ford (1995 and up)"
"Honda (up to 2015)"
"Kia or Chevy (any)

In this case, each string was the name property on an object. (Ie: you’re not looking at an array of strings in the example above.)

For display purposes, I wanted to show (in my app’s template) only what came before the first parenthesis, like so:

Toyota
Ford
Honda
Kia or Chevy

Thanks to guide on how to use regex to remove everything after a particular character, and this refresher on how .replace() works, I had this problem solved in a matter of minutes with the following expression, where params[0] is the string (more about why my method looks like this after the code):

export function stripParensFromCarData(params/*, hash*/) {
  return params[0].replace(/\(.*\)/,'');
}

I used this method in an Ember helper I wrote to format strings for display in a handlebars template. The helper was hooked up like so in the .hbs file:

{{strip-parens-from-car-data carString}}

My favorite tool for testing regular expressions as I write them is regexr.com.

AngularJS Infinite List – How to create a list that automatically adds a blank textarea as the user adds new data

This tutorial is about a neat trick you can use with ng-repeat and inputs using AngularJS. This is just one tiny part of a larger AngularJS project of mine you can explore here: Chicken Breast Meals on GitHub.

Let’s say you are building a user input form that lets the user input series of items in a list, such as ingredients in a recipe. You could have the user click a link to add a new input field before typing in each ingredient, but that’s an extra (and annoying) step nowadays for users.

What you really want is a list of inputs that grows itself, offering a new blank input in response to each addition the user makes:

dynamic_list_animation
Infinitely-expanding list grows as the user adds to it

 

PLUNKER DEMO

The rest of this tutorial uses the Chicken Breast Meals project code to explain how this feature was made.

Part 1: In the view (.html file)

The html code (and Angular directives) that create the ingredients list above is in app/views/admin/admin-edit-meal-view.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<h2>Ingredients</h2>
  <ol class="ingredients-list">
  <!-- loop through and display existing ingredients -->
    <li data-ng-repeat="ingredient in formMeal.ingredients track by $index">
    <textarea name="ingredientLines" 
              type="text"
              data-ng-model="formMeal.ingredients[$index].name"
              placeholder="Add ingredient"
              data-ng-change="changeIngredient($index)">
    </textarea>
 <!-- trash can button -->
 <a href="" data-ng-show="ingredient" 
            data-ng-click="formMeal.ingredients.splice($index,1)">
 <img src="/assets/delete.png"/></a>
 </li>
 </ol>

When the user selects a recipe to edit in the admin page, that selected recipe is represented by an object called formMeal. Inside formMeal are properties like:

  • name (which is saved as a String)
  • yield (saved as a Number)
  • cookTime (another Number)
  • ingredients (an Array of Objects)

On the <li>

The ng-repeat directive builds the list of ingredients by creating a <li> and a <textarea> for each ingredient already found in the saved recipe data.  Each ingredient has an index in the ingredients array, so we grab its name out of the array of ingredient objects like so:

formMeal.ingredients[$index].name

Immediately following the ng-repeat directive is $track by index. This bit of code is easy to overlook but it’s very important: it’s what keeps the user’s current textarea in focus while the user edits it. Without $track by index, the app kicks the user out of that text box after the first typed letter. (Ask me how much fun I had debugging this lose-focus problem…)

In the <textarea>

Each ingredient is represented by a <textarea>, and each one has its own ng-model directive pairing it with that particular index in the array.

data-ng-model="formMeal.ingredients[$index].name"

This lets us edit an existing ingredient anywhere in the list by that ingredient’s index. Since ingredients is an array, we need to pass it the index of the ingredient we’re editing via the <textarea>. (You can read more about ng-repeat and $index here in the Angular documentation.) This placeholder part is straightforward:

placeholder="Add ingredient"

This is what puts the default text into each <textarea> when the user hasn’t entered anything yet. It’s just a nice UX touch.

Finally, we have an ng-change directive. You can read more about ng-change here, basically all it does is call the method (or do the thing) you tell it to do any time there’s a change in the <textarea> it’s associated with.

data-ng-change="changeIngredient($index)"

A change to the <textarea> (ie: user typing) causes the method changeIngredient() to run with each change.

Wait, where’s changeIngredient()? It’s over in app/js/controllers/cbm-admin-controller.js, which we will look at next.

Part 2: In the controller (.js file)

Now we’re inside app/js/controllers/cbm-admin-controller.js looking at the changeIngredient() method.

We already saw that whenever the user updates text inside one of those <textarea> regions, this method gets called. (If you were to put a console log inside changeIngredient(), you would see it called every time you typed a letter into the textarea.)

1
2
3
4
5
$scope.changeIngredient = function(index) {
   if (index == $scope.formMeal.ingredients.length -1){
     $scope.formMeal.ingredients.push('');
   }
};

changeIngredient(index) checks the index that’s been passed in:

  • if that index is at the end of the array (ie: its index number is one less than the array’s length), then we are editing the last ingredient in the list and we need to push an empty ingredient (”) to the ingredients array to make the empty box appear at the end
  • if that index is not at the end of the array, we just update whatever’s at this index since it’s an ingredient that already exists. This is why you don’t see an empty box get added to the end of the list if you’re editing a field that’s not at the end.

It’s important to observe that this method works by checking that the user is editing the last index (which is always the empty <textarea>). This is how we  don’t spawn new, empty textareas for editing earlier ingredients in the list.

What updates the ingredients list automatically? That’s Angular’s two-way data binding at work. Any time you update a model the change happens in real time.  If you’re new to Angular, here’s a Plunker demonstrating a very simple implementation of Angular’s two-way data binding.

Part 3: Offering an empty field by default

When you initialize your data or your app, you’ll need to include something like:

$scope.formMeal.ingredients = [''];

or

$scope.ingredients.push('');

so that the ingredients list has an empty one in it by default. Your implementation needs will vary, of course, but hopefully this little guide gave you enough of a start to build this “infinity list” into your own AngularJS form!

Don’t miss the Plunker demo of a simplified version of this feature that you can play with and adapt to your own project.

Book Review: You Don’t Know JS – Scope & Closures by Kyle Simpson

scope_and_closures_book_JS_kyle_simpson
Scope & Closures by Kyle Simpson

If you’re an intermediate JavaScripter who’s tired of weighty tomes and arcane examples, You Don’t Know JS – Scope & Closures by Kyle Simpson is right up your alley. This smart book takes a laser-focused look at scope and closures in JavaScript.

My rating: 5/5

Who it’s for: Intermediate JavaScripters. If you’ve heard of scope, closures, JS compiling theory, but aren’t sure you really understand them as well as you should, then this book is for you.

Review

Let me preface this review by saying I’m not a big fan of coding books.

I have been frustrated by out-of-date books, untested code, and overly complex explanations from coding wizards who have long since forgotten what it’s like to be a newbie. I’ve always been more of an in-the-trenches doer than an ivory tower studier, anyway.

So, I wasn’t expecting to like Kyle Simpson’s You Don’t Know JS: Scope & Closures book so much. A programmer friend insisted I read it, and 87 pages of golden JS secrets and epiphanies later, I’m glad I did.

This book is…

  1. Brief. No long-winded explanations or storytelling.
  2. Focused. One topic, explored deeply FTW.
  3. Short examples, usually just a handful of lines total.
  4. Easy-to-follow examples with good style choices, such as verbose variable names and comments listing the expected result.
  5. Concepts are explained and re-explained before moving on. This is complicated stuff for us intermediate JavaScripters, and he takes the time to attack topics from multiple angles.

Highlights

You Don’t Know JS – Scope & Closures covers:

  • variables: declaring, setting, and updating
  • scope
  • lexing
  • hoisting
  • closures
  • how the JavaScript compiler reads code
  • tokenizing

This book deserves credit for explaining the compiler’s process of operations in a way that actually clicked for me.

I also loved the short examples. They were easy to follow, none of that 30+ lines of code spread across two pages stuff you see in other books.

The book’s small size is a plus.  I took it with me on a day trip – hooray for books that aren’t the size of my laptop.

Criticisms?

The only thing I might say is that some examples in the book are like, “Yeah, duh, don’t do it that way” but to be honest, I probably had to be told some of these “duh” things myself when I was starting out a few years ago.

Overall, I’d give this book an A+. It fits into the vast gulf between “total n00b” and “JavaScript Jedi”.

Check it out on Amazon.com for the current price (as well as any coupons and deals that might be running).

Note to readers: TILCode is an Amazon Affiliate. Purchases made through some links on this site help support the site at no extra cost to you. Read the full disclosure here.

Read this: Airbnb’s Excellent JavaScript style guide

Today I learned… that Airbnb has a fantastic JavaScript “style guide” available for free on github. The guide is light on long-winded explanations and big on DO and DON’T examples. Check it out, it’s a 15 min read at most.

Here are just a few of the things I learned from it:

Declaring multiple variables

A long list of variable declarations should be done with the unassigned variables last, and all declarations can share one use of var.

// multiple var declarations like so:
var items = getItems(),
    daytime = true,
    length,
    i;

I’m definitely guilty of var var var var var… but I’m not sure how I feel about this particular style. I like the clarity and editability of beginning each line with var, but for declaring lots of like items, I can see the usefulness of this style.

Shortcuts for the win

Instead of writing “if this thing is greater than zero”, you can just write “if this thing”.

Here’s an example:

// bad
if (cars.length > 0) {
  // ... code here
}

// good
if (cars.length) {
  // ... code here
}

Easy enough.

Comment with good style

Oops, I’ve definitely been getting this one wrong. Comments belong on their own line, not off to the right of the line the comment explains.

// bad
var active = true;  // is current tab

// good
// is current tab
var active = true;

Guilty. I’ll quit doing this, as tempting as it is for the sake of shorter files…

Saving a reference to “this”

Oops, here’s another mea culpa. I’ve been saving reference to “this” as “self”, but the style guide suggests _this as a better alternative.

I’m inclined to agree – I found “self” confusing the first time I encountered it, and its relation to “this” wasn’t immediately apparent.

// bad
function() {
  var self = this;
  return function() {
    console.log(self);
  };
}

// bad
function() {
  var that = this;
  return function() {
    console.log(that);
  };
}

// good
function() {
  var _this = this;
  return function() {
    console.log(_this);
  };
}

Those are just a handful of the discoveries I made while exploring this guide.

Be sure to check it out yourself and see what you could be doing better, and don’t miss the giant list of resources at the bottom of the page!

Declaring a variable as a number before adding to it with +=

Today I learned… that you have to explicitly declare a number variable as a number before you can increment it with += in JavaScript.

This is probably a boneheaded newbie mistake, but it had me stumped for several minutes. I declared a variable, var total; and then tried to add to it by writing total +=5.  And then I scratched my head as my code returned NaN.

1
2
3
4
var total;
 
total += 5;
console.log(total); //prints "NaN"

This happens because “undefined” and zero are not equivalent in JavaScript! 

Even though JavaScript isn’t “strongly typed”, you can’t add numbers to something that isn’t a number yet.

Declaring total by setting it to an actual number, ie: var total = 0, fixed my “NaN” problem.

1
2
3
4
var total = 0;
 
total += 5;
console.log(total); //prints a 5