Nikola Brežnjak blog - Tackling software development with a dose of humor
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Home
Daily Thoughts
Ionic
Stack Overflow
Books
About me
  • Home
  • Daily Thoughts
  • Ionic
  • Stack Overflow
  • Books
  • About me
Nikola Brežnjak blog - Tackling software development with a dose of humor
Breaking News, Ionic

Ionic announces Ionic Lab – a GUI tool replacement for Ionic CLI

From the official blog post, Ionic just announced a new shiny tool called Ionic Lab; which is a GUI tool that tends to be a replacement for the well know Ionic CLI for those who don’t quite like the CLIs.

Hmm, anyone like that reading this blog? I personally like using CLIs better, in general, but that’s just me I guess. <3 Terminal. However, I just might do an exception with this tool.

Currently, they only have a version for Mac (with a Windows version supposedly coming soon. Edit: windows version has been announced today (16.09.2015), and you can learn more about it on their blog) and you can download it from the official download page. Once you download the IonicLab.dmg file, just run it and drag the icon in the Applications folder, as instructed by the installer:

ionicLabInstall

If you try to run the app via Spotlight, you may get an error “Ionic Lab can’t be opened because it is from an unidentified developer” like shown on the image below:

ionicLabRunError

If you’re quite new to the Mac world (as I am), you can resolve this issue by opening up your Applications folder, locating Ionic Lab icon and right clicking the icon and selecting Open.

ionicLabApplicationsFolder

Now a similar popup will appear, but this time  with the Open option:Screen Shot 2015-08-12 at 23.37.06

Select the Open option and you should get the initial Ionic Lab screen:

Screen Shot 2015-08-12 at 23.44.55

I tested this by dropping my IonicAdMob (link to Github project) application to it, and this is what happened:

Screen Shot 2015-08-12 at 23.48.06

At this point, even though I like CLIs more (as I noted in the introduction) I must say this is pretty awesome. Additionally, if you click on the PLUGINS tab you will see:

Screen Shot 2015-08-12 at 23.49.49

Here you can literally install the plugins by simply clicking on the checkboxes.

What’s even more exciting is that they announced that in the future they’re looking to improve it in terms of:

  • including a one-click system setup
  • adding Cordova plugin search
  • adding Ionic resources generation for icons and splash screens
  • adding Ionic Platform integration for push notifications
  • adding Ionic Creator integration
  • and quite some more things, which you can learn more from their blog post

All this, I must say, is pretty damn awesome and I’m really rooting for them so that they make all their plans into reality.

Bye bye, I’m going to play with my new shiny tool now for a while…

Ionic, Stack Overflow

How to redirect users if there is no Internet connection in Ionic framework?

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts, I will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

As you may know, I’m really into Ionic framework lately and am helping out on StackOverflow with the knowledge I gained so far with the framework. In the last 30 days, I’m the top answerer in the ionic tag, and am currently #6 All time answerer:

soIonic

I answered this question by userFlorin Simion:

I want to redirect users to a different page when they’re not connected to the Internet.

My only question is why this is working:

if (window.Connection) {
    if(navigator.connection.type == Connection.NONE) {
        alert("Please connect to internet");
    }
}

and this is not

if (window.Connection) {
    if(navigator.connection.type == Connection.NONE) {
        $scope.state.go('offline');  
    }
}

My answer was:

Because you’re using $state the wrong way. Instead of this:

$scope.state.go('offline');

You should do it like this:

$state.go('offline');

Remember to inject $state in your controller. More information about $state from official docs.

By “Remember to inject $state in your controller” I’m referring, for example, to this:

app.controller('ctrl', function ($scope, $state) {
    $scope.changeState = function () {
        $state.go('someplaceNice');
    };
});

If you would want a more in-depth tutorial about network information gathering in Ionic make sure you check the Check network information change with Ionic framework tutorial.

Ionic, Stack Overflow

Use Ionic or Cordova?

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts, I will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

As you may be aware of, lately I’m really into Ionic framework and am helping out on StackOverflow with the knowledge I gained so far with the framework. In the last 30 days, I’m the top answerer in the ionic tag, and am currently #6 All time answerer:

soIonic

I answered this question by user user1365697:

We want to build a simple application that use a lot of videos and images. The application should run on different mobile devices running Andriod and iPhone operating systems. Does Ionic also convert each application to all mobiles options? What do you suggest to use Cordova or Ionic?

My answer was:

 

Disclamer: This will sound like advertisement, so I have to say I’m in no way affiliated with Ionic, I just happen to like it so much that I’m sharing the love for it.

Ionic is so much more than “just” an UI framework. Ionic allows you to:

  • generate icons and splash screens for all devices and device sizes with a single command: ionic resources. This alone saves you at least a day of image preparing for various sizes.
  • instantly update your apps with code changes, even when running directly on your device with ionic run --livereload
  • build and test iOS and Android versions side-by-side and see changes instantly with ionic serve --lab
  • share your Ionic apps with clients, customers, and testers all around the world without ever going through the App Store with ionic share
  • easily accessing the full native functionality of the device using ngCordova (here you get to use any Cordova plugin – so Ionic is indeed much more than Cordova per se)

Also, they’re building a full-stack backend services and tools for your Ionic app like Deploy (for deploying a new version without going through Apple review process!), Analytics, Push notifications.

Ionic CLI (command line interface) uses Cordova in the backend and allows you to build (directly using Ionic CLI) apps for iOS and Android (you by doing ionic build ios or ionic build androidand woila).

Ionic uses Angular as a frontend framework so if you’re familiar with it it will come as a bonus. They’reworking closely with the Angular 2.0 team too.

All in all, I personally think Ionic has a bright future, so if nothing else – give it a try I bet you’ll like the ease of making an app with it.

NodeJS

npm ERR! peerinvalid The package node-inspector does not satisfy its siblings’ peerDependencies requirements

Recently I was reinstalling ionic and cordova with:

npm install -g cordova ionic

but I got the following error:

    E:\IonicTesting>npm install -g cordova ionic
    npm WARN engine [email protected]: wanted: {"node":"~0.10.x"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN engine [email protected]: wanted: {"node":">=0.6","npm":"1"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN engine [email protected]: wanted: {"node":"0.8.x || 0.10.x"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN engine [email protected]: wanted: {"node":"~0.10.x"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN engine [email protected]: wanted: {"node":">=0.6","npm":"1"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN installMany normalize-package-data was bundled with [email protected], but bundled package wasn't found in unpacked tre
    e
    C:\Users\Nikola\AppData\Roaming\npm\cordova -> C:\Users\Nikola\AppData\Roaming\npm\node_modules\cordova\bin\cordova
    npm WARN engine [email protected]: wanted: {"node":"0.8.x || 0.10.x"} (current: {"node":"0.12.7","npm":"2.11.3"})
    npm WARN installMany normalize-package-data was bundled with [email protected], but bundled package wasn't found in unpacked tre
    e
    C:\Users\Nikola\AppData\Roaming\npm\ionic -> C:\Users\Nikola\AppData\Roaming\npm\node_modules\ionic\bin\ionic
    npm WARN unmet dependency C:\Users\Nikola\AppData\Roaming\npm\node_modules\generator-ionic requires cordova@'^4.2.0' but
     will load
    npm WARN unmet dependency C:\Users\Nikola\AppData\Roaming\npm\node_modules\cordova,
    npm WARN unmet dependency which is version 5.1.1
    npm ERR! Windows_NT 6.1.7601
    npm ERR! argv "C:\\NodeJS\\\\node.exe" "C:\\NodeJS\\node_modules\\npm\\bin\\npm-cli.js" "install" "-g" "cordova" "ionic"
    
    npm ERR! node v0.12.7
    npm ERR! npm  v2.11.3
    npm ERR! code EPEERINVALID
    
    npm ERR! peerinvalid The package node-inspector does not satisfy its siblings' peerDependencies requirements!
    npm ERR! peerinvalid Peer [email protected] wants node-inspector@~0.7.0
    
    npm ERR! Please include the following file with any support request:
    npm ERR!     E:\IonicTesting\npm-debug.log

At first I thought the reason is that I may have had an older version of node or npm but wasn’t the case because my versions were up to date (date of this post: 03.08.2015):

E:\IonicTesting>node -v
v0.12.7
E:\IonicTesting>npm -v
2.11.3

Also, I did try:

npm update -g

and

npm cache clean

as noted in the few StackOverflow answers, but it didn’t help. After a bit of googling and messing around I realized (an idea came from this StackOverflow answer) that I could try uninstalling the dependencies which were messing with me:

npm uninstall -g node-inspector
npm uninstall -g strong-cli
npm install -g generator-karma

After this I ran

npm update -g

and then, to finally install Ionic and Cordova, I ran:

npm install -g cordova ionic

And, what do you know – it worked. Hope this helps someone!

Ionic, Stack Overflow

Show Interstitial Ad via AdMob in Ionic every 2 minutes

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts I will will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

I actually answered this question by userArlind a:

I’m using AdMob plugin in Ionic and with this code I show an Interstital ad:

function initAd(){

 // it will display smart banner at top center, using the default options
 if(AdMob) AdMob.createBanner( {
                          adId: admobid.banner,
                          bannerId: admobid.banner,
                          position:AdMob.AD_POSITION.BOTTOM_CENTER,
                          autoShow: true,
                          isTesting: false,
                          success: function(){
                          console.log('banner created');
                          },
                          error: function(){
                         console.log('failed to create banner');
                          }
                          } );

                                       window.AdMob.prepareInterstitial( 
                           {adId:admobid.interstitial, autoShow:false} );
    window.AdMob.showInterstitial();

 }

Is there a way to show intersitial ad every 2 minutes? Someone told me to add this:

setInterval(showInterstitial,1*60*1000)

but I don’t know where to add?

My answer was:

 

If you would like to show it every 2 minutes you should use:

setInterval(window.AdMob.showInterstitial, 2*60*1000);

and you should add it just before the closing bracket of your initAdd function:

function initAd(){


 // it will display smart banner at top center, using the default options
 if(AdMob) AdMob.createBanner( {
                          adId: admobid.banner,
                          bannerId: admobid.banner,
                          position:AdMob.AD_POSITION.BOTTOM_CENTER,
                          autoShow: true,
                          isTesting: false,
                          success: function(){
                          console.log('banner created');
                          },
                          error: function(){
                         console.log('failed to create banner');
                          }
                          } );

                                       window.AdMob.prepareInterstitial( 
                           {adId:admobid.interstitial, autoShow:false} );
    window.AdMob.showInterstitial();
  
  
  
  //!!!add the code here!!! - so, just paste what I wrote above:
  setInterval(window.AdMob.showInterstitial, 2*60*1000);

 }

You can see a simple setInterval usage on this jsFiddle example:

function a(){
    alert("hi every 2 seconds");
};

setInterval(a, 2*1000);

The reason why you shouldn’t call it like this (note the brackets after a): setInterval(a(), 2*1000); is that then your function would be called only once (you would see only one alert popping up). Example on jsFiddle:

function a(){
    alert("hi every 2 seconds");
};

setInterval(a(), 2*1000);
Angular, Stack Overflow

Reference the inputs created with ng-repeat in angular based on the number of variable options

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts I will will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

My question was:

The problem I’m facing, as outlined in the code, is that I can’t seem to find out how to bind the second checkboxes (created with ng-repeat) to some model which I would then be able to use further down the code (showing/hiding yet another set of options). Also, I managed to show the additional number of inputs based on the count parameter in the $scope.availableOptions by using the $scope.getItterator function, but now I don’t see how would I access the values of these checkboxes? I know I have to somehow use the option “ng-model” but am failing to do so, so any help appreciated.

My code is here, but am showing it here too:

HTML:

<div ng-controller='MyCtrl'>
    Show additional options <input type="checkbox" ng-model="additionalOptions">
    <div ng-show="additionalOptions">
        <ul>
            <li ng-repeat="option in availableOptions">
                <label class="checkbox" for="opt_{{option.id}}">
                    <input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" />
                    {{option.name}}

                    <ul ng-show="if the upper checkbox is clicked">
                        <li>
                            <input type="text" ng-repeat="i in getItterator(option.count)" ng-model="SOME_VALUE_TO_BE_USED_BELOW"/>
                            Output the value based on what's entered above in the textboxes (SOME_VALUE_TO_BE_USED_BELOW)
                        </li>   
                    </ul>
                </label>
            </li>
        </ul>
    </div>
</div>

and my js:

function MyCtrl($scope) {
    $scope.availableOptions = [{"id":"1","name":"easy","count":"2"},{"id":"2","name":"medium","count":"3"},{"id":"3","name":"hard","count":"2"}];

    $scope.getItterator=function(n){
        var a = new Array();

        for(var i=1; i <= n; i++)
            a.push(i);

        return a;       
    };
}

The answer, by user Khanh TO, was:

Try ng-model="option.checked":

<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" ng-model="option.checked"/>

And then you can access this property further below like this:

<ul ng-show="option.checked">

DEMO

If you need to also reference the text box inputs. You create a new property (values) on the option. Like this:

{"id":"1","name":"easy","count":"2",values:[]}

Html:

<div ng-repeat="i in getItterator(option.count)">
     <input type="text"  ng-model="option.values[$index]"/>
      {{option.values[$index]}}
</div>

DEMO

CodeProject, MEAN

How to add a comment field to MEAN.js Article example

MEAN_Grunt_604x270

If you happen to like the image above, and you’re thinking to yourself how cool it would look like as a sticker, take a look at a few that I made.

TL;DR

In my previous tutorial about the MEAN stack, I showed you how to get your MEAN stack up and running in less than a minute. In this tutorial I’m going to show you how to add a comment field to an existing MEAN.js Article example. You can see the finished application on http://mean.nikola-dev.com, and you can clone the source on GitHub.

I actually answered the question Adding comments to MEAN.JS articles on StackOverflow, and this posts is kind of an addition to that answer, with pictures (everyone likes pictures, right? 😉).

[toc]

Starting point

So, if you’ve followed the (ah, yet again mentioned) previous tutorial you have a running MEAN.js example on your DigitalOcean Droplet, whose front page looks like the image below if you’re logged in. You can simply register via mail (I didn’t implement any other methods like Facebook, Google, LinkedIn or GitHub for this tutorial).

Screen Shot 2015-06-28 at 14.32.35

Please note that yes, you can run this example locally on your computer too, but you would have to manually install the whole MEAN stack (namely MongoDB, Express.js and Node.js). If you wish to do so, you can take a look at the steps needed to do this from a rather popular tutorial How to get started on the MEAN stack. Rest of the tutorial, however, assumes you are testing this on DigitalOcean Droplet.

How to add a subdomain for Nodejs application on DigitalOcean droplet

When I was preparing this post I bought a domain just for testing purposes called nikola-dev.com and I wanted to have Node.js apps running on this VPS (behind a NGINX running as proxy, as we set it up in previous tutorial) but that they would be accessible from different subdomains (for example mean.nikola-dev.com). Below are the steps I needed to take in order to make this happen:

  1. Buy a domain (clearly you have done so smileyGlasses)
  2. Edit the Nameserver information in the admin dashboard of your domain provider (where you bought the domain) to the following three records:
    ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com
  3. Add the domain on DigitalOcean DNS settings page:
    digitalOcean_dns
  4. Delete /etc/nginx/sites-enabled/default
  5. Create /etc/nginx/sites-available/nikola-dev.com file with the following content (this will be a simple single HTML file which will list the available test apps on this server):
    server {
        listen 80;
        server_name nikola-dev.com;
        root /var/www/nikola-dev.com/public_html;
    }
  6. Create /etc/nginx/sites-available/mean.nikola-dev.com file with the following content (this will serve the actual Node.js app that we’re building in this tutorial):
    server {
        listen 80;
    
        server_name mean.nikola-dev.com;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
  7. Restart NGINX:
    sudo service nginx restart

Adding a comment field to Article example

  1. In the file app/models/article.server.model.js add:
    comment: {
    	type: String,
    	default: '',
    	trim: true
    },

    For the reference, the whole app/models/article.server.model.js file contents should look like this:

    'use strict';
    
    /**
     * Module dependencies.
     */
    var mongoose = require('mongoose'),
            Schema = mongoose.Schema;
    
    /**
     * Article Schema
     */
    var ArticleSchema = new Schema({
            created: {
                    type: Date,
                    default: Date.now
            },
            title: {
                    type: String,
                    default: '',
                    trim: true,
                    required: 'Title cannot be blank'
            },
            content: {
                    type: String,
                    default: '',
                    trim: true
            },
            user: {
                    type: Schema.ObjectId,
                    ref: 'User'
            },
            comment: {
                    type: String,
                    default: '',
                    trim: true
            }
    });
    
    mongoose.model('Article', ArticleSchema);
  2. In the file public/modules/articles/views/create-article.client.view.html add the following content before the submit button:
    <div class="form-group">
    	<label class="control-label" for="comment">Comment</label>
    	<div class="controls">
    		<textarea name="comment" data-ng-model="comment" id="comment" class="form-control" cols="30" rows="10" placeholder="Comment"></textarea>
    	</div>
    </div>

    For the reference, the whole public/modules/articles/views/create-article.client.view.html file contents should look like this:

    <section data-ng-controller="ArticlesController">
            <div class="page-header">
                    <h1>New Article</h1>
            </div>
            <div class="col-md-12">
                    <form name="articleForm" class="form-horizontal" data-ng-submit="create()" novalidate>
                            <fieldset>
                                    <div class="form-group" ng-class="{ 'has-error': articleForm.title.$dirty && articleForm.title.$invalid }">
                                            <label class="control-label" for="title">Title</label>
                                            <div class="controls">
                                                    <input name="title" type="text" data-ng-model="title" id="title" class="form-control" placeholder="Title" required>
                                            </div>
                                    </div>
                                    <div class="form-group">
                                            <label class="control-label" for="content">Content</label>
                                            <div class="controls">
                                                    <textarea name="content" data-ng-model="content" id="content" class="form-control" cols="30" rows="10" placeholder="Content"></textarea>
                                            </div>
                                    </div>
    
    								<div class="form-group">
    								        <label class="control-label" for="comment">Comment</label>
    								        <div class="controls">
    								                <textarea name="comment" data-ng-model="comment" id="comment" class="form-control" cols="30" rows="10" placeholder="Comment"></textarea>
    								        </div>
    								</div>
    								
                                    <div class="form-group">
                                            <input type="submit" class="btn btn-default">
                                    </div>
                                    <div data-ng-show="error" class="text-danger">
                                            <strong data-ng-bind="error"></strong>
                                    </div>
                            </fieldset>
                    </form>
            </div>
    </section>
  3. In the file public/modules/articles/controllers/articles.client.controller.js adjust the create function to be:
    var article = new Articles({
    title: this.title,
    content: this.content,
    comment: this.comment
    });

    For the reference, the whole public/modules/articles/controllers/articles.client.controller.js file contents should look like this:

    'use strict';
    
    angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
            function($scope, $stateParams, $location, Authentication, Articles) {
                    $scope.authentication = Authentication;
    
                    $scope.create = function() {
                            var article = new Articles({
                                    title: this.title,
                                    content: this.content,
                                    comment: this.comment
                            });
                            article.$save(function(response) {
                                    $location.path('articles/' + response._id);
    
                                    $scope.title = '';
                                    $scope.content = '';
                            }, function(errorResponse) {
                                    $scope.error = errorResponse.data.message;
                            });
                    };
    
                    $scope.remove = function(article) {
                            if (article) {
                                    article.$remove();
    
                                    for (var i in $scope.articles) {
                                            if ($scope.articles[i] === article) {
                                                    $scope.articles.splice(i, 1);
                                            }
                                    }
                            } else {
                                    $scope.article.$remove(function() {
                                            $location.path('articles');
                                    });
                            }
                    };
    
                    $scope.update = function() {
                            var article = $scope.article;
    
                            article.$update(function() {
                                    $location.path('articles/' + article._id);
                            }, function(errorResponse) {
                                    $scope.error = errorResponse.data.message;
                            });
                    };
    
                    $scope.find = function() {
                            $scope.articles = Articles.query();
                    };
    
                    $scope.findOne = function() {
                            $scope.article = Articles.get({
                                    articleId: $stateParams.articleId
                            });
                    };
            }
    ]);
    
  4. In the file public/modules/articles/views/view-article.client.view.html add this just before the closing section tag:
    <p data-ng-bind="article.comment"></p>

    For the reference, the whole public/modules/articles/views/view-article.client.view.html file contents should look like this:

    <section data-ng-controller="ArticlesController" data-ng-init="findOne()">
            <div class="page-header">
                    <h1 data-ng-bind="article.title"></h1>
            </div>
            <div class="pull-right" data-ng-show="authentication.user._id == article.user._id">
                    <a class="btn btn-primary" href="/#!/articles/{{article._id}}/edit">
                            <i class="glyphicon glyphicon-edit"></i>
                    </a>
                    <a class="btn btn-primary" data-ng-click="remove();">
                            <i class="glyphicon glyphicon-trash"></i>
                    </a>
            </div>
            <small>
                    <em class="text-muted">
                            Posted on
                            <span data-ng-bind="article.created | date:'mediumDate'"></span>
                            by
                            <span data-ng-bind="article.user.displayName"></span>
                    </em>
            </small>
            <p class="lead" data-ng-bind="article.content"></p>
            <p data-ng-bind="article.comment"></p>
    </section>
  5. This is it, now you have a new field comment for each article:
    meanCommentAddingOnce added, you’ll see the comment in the article list:meanCommentAddedJPG
  6. What you should do now, and I hope it’s clear form these instructions here, is alter the editing part of the articles, so that they include the comment field.

Where to go from here?

This tutorial should have given you the basic understanding on how to add additional fields to the MEAN.js Article example, and you should be confident enough to starting adding your own fields and altering the example to your liking.

In the next tutorial we’ll take a look at how to add Image CRUD module to MEAN.js application with a single Yeoman command (I will update the link here once the tutorial is finished).

If you want to learn more about the MEAN stack, take a look at the blog2book Getting MEAN with MEMEs (yes, you can download it for free, though a coffee would be nice smileyGlasses).

Ionic, Stack Overflow

cordova-plugin-whitelist Error 404 not found

profile for Nikola at Stack Overflow, Q&A for professional and enthusiast programmers
I’m a big fan of Stack Overflow and I tend to contribute regularly (am currently in the top 0.X%). In this category (stackoverflow) of posts I will will be posting my top rated questions and answers. This, btw, is allowed as explained in the meta thread here.

My question was:

I tried to run this code: cordova plugin add cordova-plugin-whitelist but what I keep getting is this:

Fetching plugin "cordova-plugin-whitelist" via plugin registry Error: 404 Not Found: cordova-plugin-whitelist at RegClient.<anonymous> (/usr/local/lib/node_modules/cordova/node_modules/cordova-lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:304:14) at Request._callback (/usr/local/lib/node_modules/cordova/node_modules/cordova-lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:246:65) at Request.self.callback (/usr/local/lib/node_modules/cordova/node_modules/cordova-lib/node_modules/npm/node_modules/request/request.js:236:22) at Request.emit (events.js:98:17) at Request.<anonymous> (/usr/local/lib/node_modules/cordova/node_modules/cordova-lib/node_modules/npm/node_modules/request/request.js:1142:14) at Request.emit (events.js:117:20) at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/cordova/node_modules/cordova-lib/node_modules/npm/node_modules/request/request.js:1096:12) at IncomingMessage.emit (events.js:117:20) at _stream_readable.js:943:16 at process._tickCallback (node.js:419:13)

Any ideas?

I actually found the answer to this myself:

From an official blog post, Cordova is moving their plugins to npm.

I installed the cordova-plugin-whitelist easily now with npm:

npm install cordova-plugin-whitelist
CodeProject, MEAN

How to get your MEAN stack up and running in less than a minute

Over the past year I’ve tried lots of options for hosting my MEAN applications, and finally I’ve settled for DigitalOcean. It’s true what they advertise – that you can have a SSD cloud server up and running in less than 55 seconds. However, you don’t have to go spending your hard earned cash just yet – I have a special deal with DigitalOcean and you can signup via this link and get 10$ immediately, which will be enough for 2 full months of non stop server running. They even provide you with API so that you can control your server, and this tutorial shows you how.

I don’t want to make it look like I’m pushing you on DigitalOcean – you can sign up with someone else if you like, I just recommend them because I had a good experience with them in the past and because it’s so easy to get a MEAN stack all pre-installed (more on this in a bit) and ready for use.

Create a droplet

Once you complete the sign up on DigitalOcean  you will be presented with a similar screen, as show on the image below, where you have to click on the Create Droplet button:

DO_1_createDroplet

Next, you have to name your droplet (cool name the folks at DigitalOcean chose to call their server instances) and select the size (the smallest one will be just fine here), just as it’s shown on the image below:

DO_2_nameAndSize

After this, you have to choose a region, as shown on the image below. Naturally, you’ll want to choose some location which is closer to your targeted audience.

DO_3_region

Now comes the most awesome part. In Select Image section you have tons of options ranging from the barebones distributions (Centos, Ubuntu, Debian, etc.), to the pre-built stacks (LAMP, LEMP, WordPress, ROR, MEAN, etc.) like shown on the image below. Here you have to choose the MEAN on 14.04 option (YMMV on the exact number), and this is awesome because with this droplet you won’t have to go through the hassle of installing Node.js, Express and MongoDB as we did in the first tutorial – it will be already done and waiting for you! B-E-A-utiful!

DO_4_image

Then, just wait a few seconds and your droplet will be ready:

DO_5_waiting

You’ll be redirected to the dashboard (once the droplet is created) which will look something like the image below:

DO_6_created

Connect to the droplet

On your email address you will receive instructions which will look something like on the image below:

DO_7_email

Now, using a SSH client of your choice (I’m currently on Windows so not much leeway here :)) connect to the droplet. The image below shows the setting from the Putty SSH client on Windows:

DO_8_putty_2

You have to connect with the root user and the password that was emailed to you. However, immediately upon logging in you will get a notification that you have to change the root’s password, as shown on the image below:

DO_9_rootLogin

Create a new user

Using root user in linux is bad practice, so now you’re going to create a new user with the following command:

useradd nikola

Of course, you can use any username you want. After this add the user to the sudo group by executing the following command:

gpasswd -a nikola sudo

The sudo group enables the user nikola to use the sudo command when using some commands that are restricted to root user. You can learn more about sudo here. The image below shows the example of the commands I just listed:

DO_10_userAdd

Run

Now just run

grunt

and if you visit your ip address on port 3000 you should see:

Screen Shot 2015-06-28 at 14.32.35

What you now have running is a well known MEAN.js framework. You may have also heard about MEAN.io and you can learn about the difference in my post about MEAN.io vs MEAN.js.

Use your own domain

In case you bought (or have somewhere hanging in the closet from the 90’s .com boom) a domain that you would like to use to point to your droplet you have to go to the DNS settings and add a domain like shown on the image below:

DO_11_DNS

Also, in your domain registrar (where you bought your domain – think Godaddy, Namecheap, Hostgator, etc.) you have to set the corresponding nameservers to:

  • ns1.digitalocean.com
  • ns2.digitalocean.com
  • ns3.digitalocean.com

You can learn more about this on the official Digital Ocean guide.

Using PM2

Running your Node.js application by hand is, well, not the way we roll. Imagine restarting the app every time something happens, or god forbid application crashes in the middle of the night and you find about it only in the morning – ah the horror. PM2 solves this by:

  • allowing you to keep applications alive forever
  • reloading applications without downtime
  • facilitating common system admin tasks

To install PM2, run the following command:

sudo npm install pm2 -g

To start your process with PM2, run the following command (once in the root of your application):

pm2 start server.js

As you can see from the output shown on the image below, PM2 automatically assigns an App name (based on the filename, without the .js extension) and a PM2 id. PM2 also maintains other information, such as the PID of the process, its current status, and memory usage.

PM2

As I mentioned before, the application running under PM2 will be restarted automatically if the application crashes or is killed, but an additional step needs to be taken to get the application to launch on system startup (boot or reboot). The command to do that is the following:

pm2 startup ubuntu

The output of this command will instruct you to execute an additional command which will enable the actual startup on boot or reboot. In my case the note for the additional command was:

sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u nikola

If you want to learn more about the additional PM2 options you can take a look at this post.

Using NGINX as a Reverse proxy in front of your Node.js application

Though this step is not mandatory, there are several benefits of doing so, as answered in this Stack Overflow question:

  • Not having to worry about privileges/setuid for the Node.js process. Only root can bind to port 80 typically. If you let nginx/Apache worry about starting as root, binding to port 80, and then relinquishing its root privileges, it means your Node app doesn’t have to worry about it.
  • Serving static files like images, CSS, js, and HTML. Node may be less efficient compared to using a proper static file web server (Node may also be faster in select scenarios, but this is unlikely to be the norm). On top of files serving more efficiently, you won’t have to worry about handling eTags or cache control headers the way you would if you were servings things out of Node. Some frameworks may handle this for you, but you would want to be sure. Regardless, still probably slower.
  • More easily display meaningful error pages or fall back onto a static site if your node service crashes. Otherwise users may just get a timed out connection.
  • Running another web server in front of Node may help to mitigate security flaws and DoS attacks against Node. For a real-world example, CVE-2013-4450 is prevented by running something like Nginx in front of Node.

So, with being convinced that having NGINX in front of Node.js application is a good thing, following are the steps on how to install and configure it.

First, update the apt-get package lists with the following command:

sudo apt-get update

Then install NGINX using apt-get:

sudo apt-get install nginx

Now open the default server block configuration file for editing:

sudo vi /etc/nginx/sites-available/default

and add this to it:

server {
    listen 80;

    server_name meantodo.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

This configures the web server to respond to requests at its root. Assuming our server is available at http://meantodo.com, accessing it via a web browser would send the request to the application server’s private IP address on port 3000, which would be received and replied to by the Node.js application.

Once you’re done with the setting you have to run the following command which will restart NGINX:

sudo service nginx restart

You can learn more about additional NGINX setting from quite a load of tutorials.

Faking RAM with swap

Since we chose the smallest droplet version of 512 MB we can use swap to make this droplet perform better. Swap is an area on a hard drive that has been designated as a place where the operating system can temporarily store data that it can no longer hold in RAM. For a more indepth tutorial on this you may want to check out official DigitalOcean guide.

In order to allocate a swap file space execute the following command:

sudo fallocate -l 1G /swapfile

Then restrict it to only root user by executing:

sudo chown 600 /swapfile

With the next two commands you actually setup the swap space and enable it:

sudo mkswap /swapfile
sudo swapon /swapfile

To view the swap space information you can execute:

sudo swapon -s

To enable swap automatically when the server restarts you have to add the following content to the /etc/fstab file:

/swapfile   none    swap    sw    0   0

Additionally, there are two more settings worth changing:

  • swappiness  – parameter which determines how often your system swaps data out of RAM to the swap space. The value is between 0 and 100 and represents a percentage (60 is the default, but we’ll use 10 since we’re on a VPS)
  • vfs_cache_pressure – parameter which determines how much the system will choose to cache inode and dentry information over other data (default value is 100, but we’ll use 50)

In order to make this change append the /etc/sysctl.conf file with the following content:

vm.swappiness=10
vm.vfs_cache_pressure = 50

Other security concerns

If you want to learn more on how to secure your droplet I advise you to go over the steps in the initial server setup with Ubuntu on official DigitalOcean tutorial.

A freakin’ 150+ page MEAN tutorial PDF

This is actually an excerpt from the 4 part tutorial series I wrote for HackHands. If you like you can also take a look at all those posts combined into one big PDF file via LeanPub:

Screen Shot 2015-06-28 at 14.45.42

 

P.S. It’s an intentional typo, since if you’re proud of getting something in production then it’s called a prouduction 😉

P.P.S. You can enter any amount (yes, even 0$) and I won’t take it against you ;), though a coffee would be nice smileyGlasses

hand_rock_n_roll on!

NodeJS, Quick tips

Using nginx as a reverse proxy in front of your Node.js application

This is a straight to point short tutorial on how to set up NGINX as a reverse proxy in front of a Node.js application, and although this is not mandatory, there are several benefits of doing so, as answered in this Stack Overflow question:

  • Not having to worry about privileges/setuid for the Node.js process. Only root can bind to port 80 typically. If you let nginx/Apache worry about starting as root, binding to port 80, and then relinquishing its root privileges, it means your Node app doesn’t have to worry about it.
  • Serving static files like images, CSS, js, and HTML. Node may be less efficient compared to using a proper static file web server (Node may also be faster in select scenarios, but this is unlikely to be the norm). On top of files serving more efficiently, you won’t have to worry about handling eTags or cache control headers the way you would if you were servings things out of Node. Some frameworks may handle this for you, but you would want to be sure. Regardless, still probably slower.
  • More easily display meaningful error pages or fall back onto a static site if your node service crashes. Otherwise users may just get a timed out connection.
  • Running another web server in front of Node may help to mitigate security flaws and DoS attacks against Node. For a real-world example, CVE-2013-4450 is prevented by running something like Nginx in front of Node.

So, with being convinced that having NGINX in front of Node.js application is a good thing, following are the steps on how to install and configure it.

First, update the apt-get package lists with the following command:

sudo apt-get update

Then install NGINX using apt-get:

sudo apt-get install nginx

Now open the default server block configuration file for editing:

sudo vi /etc/nginx/sites-available/default

and add this to it:

server {
    listen 80;

    server_name meantodo.com;

    location / {
        proxy_pass http://127.0.0.1:1337;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

This configures the web server to respond to requests at its root. Assuming our server is available at http://meantodo.com, accessing it via a web browser would send the request to the application server’s private IP address on port 1337, which would be received and replied to by the Node.js application.

Once you’re done with the setting you have to run the following command which will restart NGINX:

sudo service nginx restart

You can learn more about additional NGINX setting from quite a load of tutorials.

Page 9 of 13« First...«891011»...Last »

Recent posts

  • Discipline is also a talent
  • Play for the fun of it
  • The importance of failing
  • A fresh start
  • Perseverance

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (35)
  • Daily Thoughts (77)
  • Go (3)
  • iOS (5)
  • JavaScript (127)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (2)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (77)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (40)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • Windows (8)
    • C# (2)
    • WPF (3)
  • Wordpress (2)

"There's no short-term solution for a long-term result." ~ Greg Plitt

"Everything around you that you call life was made up by people that were no smarter than you." ~ S. Jobs

"Hard work beats talent when talent doesn't work hard." ~ Tim Notke

© since 2016 - Nikola Brežnjak