Check out our Angular Book Series.

How do I combine Objects in JavaScript? Use the Ellipsis Operator!

This is a followup to last week's post about using Object.assign() to combine two JavaScript objects. Today I'll show you how to use the spread, or ellipsis, operator to do the same thing.

The scenario is that we have a configuration object being passed into a method. A lot of the config values are optional, and we want to default them if they are left out before the method does it's magic. We could write a lot of manual conditions to accomplish this, like this:


function conditionalConfig(config){
if(!config.option1){
config.option1 = defaultOption1Value;
}
if(!config.option2){
config.option2 = defaultOption2Value;
}
// etc.. etc.. etc..
// do other stuff
}

The code works, but it is tedious to write. We can use the Spread Operator to simplify it.

The Spread Operator

The spread operator is an ellipsis, or three dots. It has a handful of uses, but today I'm going to show you how to combine two objects.

Start with a function and an object that contains all the default values:


function defaultConfigWithSpread(config){
defaultObject = {
option1 : 'DefaultValue1',
option2 : 'DefaultValue2',
option3 : 'DefaultValue3',
option4 : 'DefaultValue4',

Notice I didn't close the object yet. We have one more property to add to the object:


...config
}

That last property is our spread operator. It tells the underlying engine to take all the properties from the config object and copy them into the defaultObject. If a property already exists in the defaultObject, it is overwritten. If a property does not exist it will not be changed.

For demonstration purposes, log the two objects:


console.log(config);
console.log(defaultConfig);
// do other stuff
// end function
}

You can test this like this:


customConfigObject = {
option1 : 'Value1',
option2 : 'Value2',
option3 : 'Value3',
}
defaultConfigWithSpread(customConfigObject);

Look at the console output and you'll see that the original config object is unchanged, but the default object contains all the new values:

The custom values from our config argument are retained and the unset default value--option4--is set with the new config.

You have to be careful when doing this to keep around a clean version of the default object since it is modified with this approach. I addressed that by creating the default config inside the function, as opposed to some permanent store.

Play with the code here.

It is a nice shorthand to be aware about.

How do I combine Objects in JavaScript? Use object.assign()!

Let's say we have a config object being passed into a method. A lot of the config values are optional, and we want to default them if they are left out before the method does it's magic. The structure is like this:


function conditionalConfig(config){
if(!config.option1){
config.option1 = defaultOption1Value;
}
if(!config.option2){
config.option2 = defaultOption2Value;
}
// etc.. etc.. etc..
// do other stuff
}

The code works great, but it is tedious to write all those conditionals. Is there a way to simplify it? Yes there is and I'm going to talk about two ways to do that. Today we'll cover object.assign().

Object Assign

The first way to simplify this code is to use object.assign(). Object.assign() will copy all the values from one object into another. First, create an object instance with all the default values:


function defaultConfigWithAssign(config){
defaultObject = {
option1 : 'DefaultValue1',
option2 : 'DefaultValue2',
option3 : 'DefaultValue3',
option4 : 'DefaultValue4',
}

Now use Object.assign() to combine that with your function argument:


Object.assign(defaultConfig,config)
// dump to console for testing purposes
console.log(config);
console.log(defaultConfig);
// do other stuff
// end function
}

You can test this like this:


customConfigObject = {
option1 : 'Value1',
option2 : 'Value2',
option3 : 'Value3',
}
defaultConfigWithAssign(customConfigObject);

Look at the console output and you'll see that the original config object is unchanged, but the default object contains all the new values:

The custom values from our config argument are retained and the unset default value--option4--is set with the new config.

You have to be careful when doing this to keep around a clean version of the default object since it is modified with this approach. I addressed that by creating the default config inside the function, as opposed to some permanent store.

Play with the code here.

Next week I'm going to talk about the Spread operator which can be used to accomplish the same thing.

How do I run ES6 JavaScript code on the console?

I've been following a tutorial on using Redux and the code in the sample is ES6 code. The tutorial ran the code in the debugger of Visual Studio Code, but me being an IntelliJ user could not find an parallel way to run the code.

I created an Index.html file that loaded the JS file, but nothing happened. I assume because the ES6 syntax used in the sample as not yet universal in the browser JS engines.

So, what next? I looked for a way to run the code at the console, and found one. With NodeJS installed:


node filename

That ran the code, and gave the same results that the tutorial got in the Visual Studio Code window. After doing that, I realized I could run the same thing in IntelliJ's terminal Window.

I'm not used to running advanced JS or TypeScript code w/o transpiling it with a tool like TypeScript, Webkit or the Angular CLI. This project started simpler, but I'm good to go now.

I hope this helps you!

How do I fix IE11 problems with CSS Calc and min-height?

I hate it when you have a problem that you cannot replicate in a simple example. That's exactly where I am. I'm working on an application built with HTML, CSS, and various JavaScript frameworks. The application requires a footer to be aligned at the bottom of the page. If the content is too large for the page, then the the footer should show up under the content. But, if the content is too small for the page, the footer should show up at the bottom of the window, or viewport.

This should be pretty simple to build using CSS and HTML:


<div class="wrapper">
Lots of Main Content and navigation and headers Here
</div>
<footer>
Some Footer Information Here that should always be at the bottom of the page
</footer>

The CSS would be something like this:


html, body {
height: 100vh;
margin : 0;
}

.wrapper {
min-height: calc(100% - 200px);
}

footer {
height : 200px;
background-color : blue;
}

The actual client project code is a lot more complex, but this gives you the gist. Play with the code here. Ignore my design skills.

The problem I was having was that IE11 seemed to have a problem with the min-height. When clicking in the page, or clicking a link to go to another page, it was as if the wrapper's min-height would shrink down on pages where the view height was greater than the actual content. This would cause the footer to jump to the middle of the page.

For the life of me, I haven't been able to create a simple sample to demonstrate this. Some part of the client's custom code seems to be causing this.

After some head banging and conferring with my team, I came up with this solution. It makes use of JavaScript and JQuery to 'hard code' the min-height on the wrapper. Instead of using the CSS Calc. this happens when the page loads and whenever the page is resized.


if(/MSIE \d|Trident.*rv:/.test(navigator.userAgent)){
function onResize(){
     /* The jquery calc code */
     $('.wrapper').css('min-height', '100%').css('min-height', '-=200px');
}

$(window).resize(function() {
onResize()
});

$(window).ready(function(){
onResize()
});

}

I used a regex trick to only execute the code for IE browsers. And I used this answer as a base for my solution.

Part of our problem solving this was my inability to create a simple reproducible case, but pouring over thousands of line of code I could not find the magic style combination that caused the 'footer jump' problem.

Frustrating; but the JS code above seems to solve the issue admirably.

Why does reloading my Angular 2 App return a 404 error?

I've been having some issues with Angular 2 [now Angular 4] and the RouterModule. I put together this screencast to demonstrate the problem and how I fixed it:

Watch For Code Changes - Building Angular 2 Applications with Gulp - Part 10

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, Part 7, Part 8, and Part 9.

There was one more thing I wanted to touch on for the purposes of this article. When changing code, I want the app to automatically be recompiled. Gulp provides built in functionality to make that happen. Iterative builds help improve performance, and get you reviewing your app in the browser without having to manually compile every time.

Watch for TypeScript changes

Create a task named buildWatch:


gulp.task('buildWatch', ['build'], function(){
}

The first thing this task does is build the application. The array before the function does this. This makes sure that we have the most recent code in the build directory before we start making changes.

Then we need to start watching for changes. We can use the watch() method of gulp to do this. First, the TypeScript files:


gulp.watch(typeScriptSource,['buildTS'])
.on('change', function(event){
console.log('File Path' + event.path);
})

The first argument to the watch() function is the glob array that points to the TypeScript source. The second argument is an array which represents the tasks to execute when a change is detected. In this case, the buildTS task is executed. When a change is detected, I chained an on() event after the watch() task. This outputs the name of the file that changed.

Let's try this:


gulp buildWatch

You should see something like this:

Notice that you are not sent back to the console prompt after running this. The task is waiting for something to happen. Change the main.ts file by adding something simple like this to the end:


console.log('something');

Then look at the console:

The changed file was output the console, and the buildTS was re-run. The buildTS task runs tslint before building the code; that has not changed.

Watch for HTML and JavaScript Changes

You can use the exact same approach for watching changes with HTML and the JS Libraries. Add these to the buildWatch task:


gulp.watch(htmlSource,['copyHTML']).on('change', function(event){
console.log('File Path' + event.path);
})
gulp.watch(javaScriptLibraries,['copyJSLibraries']).on('change', function(event){
console.log('File Path' + event.path);
})

As files are changed, the relevant tasks are rerun. I don't usually watch the Angular libraries because they are rarely changed or updated during development unless it is a big project decision.

Final Thoughts

Build scripts are important. When I started doing Angular 1 development with JavaScript, I could just use JavaScript directly in the browser and was able to push off dealing with build scripts to a future time. However, when using Angular 2 with TypeScript, the build process became much more important since a compile process is needed before you can test your code. I had to jump in earlier than I would have otherwise.

Remember, you can get all the code for this series in our seed project repository. Thank you for reading, be sure to sign up on our mailing list to get information like this direct to your inbox each month.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Production Build - Building Angular 2 Applications with Gulp - Part 9

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, Part 7, and Part 8.

Sometimes I like to create a build intended for production servers which does not include source maps. To make that happen, I use a gulp-if plugin to conditionally decide whether to generate the source maps, or not. First, install gulp-if:


npm install --save-dev gulp-if

You'll see an install screen like this:

Now, import the gulp-if library as part of the gulpfile.js:


var gulpIf = require('gulp-if');

Before we modify the buildTS task, let's add a variable named devMode:


var devMode = true;

This is the variable we will use to determine whether or not to generate the source maps. It is set to true by default. Primarily we will change this variable as part of tasks, not as a configuration option. Review the buildTS task:


gulp.task("buildTS", ["tslint"], function() {
return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(uglify())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));
});

We want to use gulp-if as part of the two source map statements. First replace the source map init statement:


.pipe(gulpIf(devMode,sourcemaps.init()))

Instead of just calling sourcemaps.init(), we now wrap it in a gulpIf. This will check the devMode variable and conditionally init the source maps.

Also change the sourcemaps.write() pipe:


.pipe(gulpIf(devMode,sourcemaps.write(mapPath)))

With the buildTS task updated, we can now create a task for building a production version of the app. The purpose of this task is to set the devMode value to false; and then run the cleanBuild task:


gulp.task('buildProd', function(){
devMode = false;
gulp.start('cleanBuild')
});

We can use gulp.start() to run the cleanBuild task. Running cleanBuild will delete the build directory, and then run the build task to compile the TypeScript files, move the HTML, and move the JavaScript libraries.

Run the task:


gulp buildProd

You should see this:

Take a look at the build directory:

You'll notice that the maps directory is missing; meaning that the sourcemaps were successfully bypassed when running the cleanBuild. We can use this same approach to perform other actions as part of a build process. In the future, I plan to make changes to the buildProd script to force the Angular application into production mode, instead of development mode by default.

What's Next?

I have one final entry prepared for this blog series. The next one will talk about recompiling code as you make changes.

Get our white paper for even more information:

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Clean Build - Building Angular 2 Applications with Gulp - Part 8

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6, and Part 7.

This part of the series will show you how to delete the build directory and produce something that I call a clean build. This is important when refactoring code, which may leave remnants of old files in the build directory.

Delete the Build Directory

To delete a directory, we can use the NodeJS Plugin, del. This isn't a Gulp plugin, but can be wrapped in a gulp task. First, install it:


npm install --save-dev del

You'll see the install screen, like this:

Next, you can load the del library inside your gulpfile.js:


var del = require('del');

Create a glob array with everything that needs to be deleted:


var deletePath = [destinationPath + '/**']

The destinationPath variable is used, with a wild card after it. This tells the del task to delete everything. Next, create the task:


gulp.task('clean', function () {
return del(deletePath);
});

The task is named clean. It calls the del() module with the deletePath value. Run the task:


gulp clean

You'll see this:

Check your project directory:

The build directory is noticeably absent, which is exactly what we want.

Run Clean, then Build

Let's combine the clean task with the build path. To do that we'll want to run the two tasks in sequence, as we don't want the clean task to delete files the build task is creating. To do that we'll use a gulp plugin named run-sequence.

Install the plugin:


npm install --save-dev run-sequence

You'll see this:

With it installed, we can create an instance of it in the gulpfile.js:


var runSequence = require('run-sequence');

Then, create the task:


gulp.task('cleanBuild', function () {
runSequence('clean', 'build');
});

I named the gulp task, cleanBuild. It uses the runSequence library to run the clean task--which deletes everything in the build directory, and the build task--which will create a fresh build.

Run the task:


gulp cleanBuild

You'll see something like this:

You see that the clean task is run first; and after it is finished the build tasks start. This will delete the build directory and all other relevant files, and then re-generate using the other tasks we wrote about earlier in this chapter.

What's Next?

The next part of this series will create what I call a production build. The final part will show you how to watch directories for changes while the code is in development.

Sign up to our mailing list to get an expanded version of this series.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Creating a Simple Build Task - Building Angular 2 Applications with Gulp - Part 7

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, Part 6.

In previous parts of this series, we created a lot of different build tasks. One for validating the TypeScript, one for compiling the TypeScript, and a few tasks for copying JavaScript and HTML files. What if we want to run them all in one command? This article will show you how.

It is pretty simple to create a Gulp task which will run multiple other Gulp tasks:


gulp.task("build", ['buildTS', 'copyJSLibraries',
'copyAngularLibraries','copyHTML']);

This creates a new Gulp task named build. The argument to the task is an array and each element of the array is a string which represents another Gulp task. We saw this approach with buildTS task built in Part 3. In that part, the tslint task was executed as part of the buildTS task. In this case, the build task does not have its own functionality it just combines together the existing tasks.

Run this task:


gulp build

You'll see something like this:

All the tasks are run, creating a build.

What's Next?

The next part of this series will show you how to delete everything in the build directory before creating the build. I call this approach a clean build.

All the information is already available, so sign up for our newsletter to start reading right away.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

Minimizing the JavaScript Code - Building Angular 2 Applications with Gulp - Part 6

This is part of an ongoing series about building Angular 2 TypeScript applications with Gulp. Start with Part 1, and then read Part 2, Part 3, Part 4, and UglifyJS. An important aspect of modern HTML5 development is to make your JavaScript files as small and optimized as possible. The minification process shortens variable names, removes whitespace, and deletes comments. It can perform other optimizations too. The purpose is to provide a smaller download to the end user. The process can, sometimes, be significantly especially with larger applications. UglifyJS is my preferred minimizer, so we'll use that.

Install gulp-uglify

The first step is to install the gulp-uglify module. Run this command:


npm install --save-dev gulp-uglify

You'll see feedback like this:

We are ready to use Uglify in our script.

Modify Gulp Script

First, load the gulp-uglify script in the gulpfile.js:


var uglify = require('gulp-uglify');
] Now, jump to the buildTS task. Here it is in the current state:


gulp.task("buildTS", ["tslint"], function() {
return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));
});

We want to run Uglify before the source map is written, but after the TypeScript is converted. Add a single line, like this:


.pipe(uglify())

The line should be placed in the script before the source maps are written:


return gulp.src(typeScriptSource)
.pipe(sourcemaps.init())
.pipe(tsProject())
.pipe(uglify())
.pipe(sourcemaps.write(mapPath))
.pipe(gulp.dest(destinationPath));

The pipe() after tsProject() calls the uglify() method. We could configure the Uglify Script with various options, but for the purposes of this sample I used the default setup.

Review the Minimized Code

Run the updated script:


gulp buildTS

See it run:

The directory structure will not have changed, but the contents of the custom JS files have. Assuming you're using our default hello world application, take a look at the app.module.js:


"use strict";var __decorate=this&&this.__decorate||function(e,o,r,t){var p,n=arguments.length,c=n<3?o:null===t?t=Object.getOwnPropertyDescriptor(o,r):t;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)c=Reflect.decorate(e,o,r,t);else for(var a=e.length-1;a>=0;a--)(p=e[a])&&(c=(n<3?p(c):n>3?p(o,r,c):p(o,r))||c);return n>
3&&c&&Object.defineProperty(o,r,c),c},core_1=require("@angular/core"),platform_browser_1=require("@angular/platform-browser"),app_component_1=require("./app.component"),AppModule=function(){function e(){}return e}();AppModule=__decorate([core_1.NgModule({imports:[platform_browser_1.BrowserModule],declarations:[app_component_1.AppComponent],bootstrap:[app_component_1.AppComponent]})],AppModule),exports.AppModule=AppModule;

This is a minimized version of the translated TypeScript code. It includes some SystemJS configuration that we didn't write manually--that was added by the TypeScript compilation. If you look closely, you see a lot of the function arguments are changed into single character values. White space and line breaks are removed. Other optimizations can be made by the Uglify library, such as variable definition optimizations. Such things are not present in the existing code.

Run the final code in the browser, and you'll find it still runs as expected, and the source maps still work.

What's Next

The next few article in this series will talk about different build techniques, and some tasks I write to handle different options. The final article of this series will show you how to build a script that will recompile your code as changes are made on the fly.

All the information is already available, so sign up for our newsletter to start reading right away.

Get our expanded 38-page version: Building Angular 2 Applications with Gulp.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.