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
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!

CodeProject, Quick tips, Wordpress

How to add excerpts to your WordPress blog homepage in a TwentyThirteen theme and not break the Codeproject importer

As you may know, CodeProject has a thing called Technical blogs which lets you publish your post on their site too, and thus widening the range of potential readers.

Thanks to a great plugin by hjgode you can automatically import your posts.

However, recently I wanted just to show excerpts of the posts on my blog homepage and in the archives. The problem was that that stopped the importer from collecting the posts that are marked with the codeproject category because the posts were too short according to their rules (1000 words minimum).

I solved this in my  TwentyThirteen theme by doing slight changes in content.php (around line 33), which by default looks like this:

<?php if ( is_search() ) : // Only display Excerpts for Search ?>

This line displays excerpts only on a search page, and to show excerpts on homepage I did:

<?php if ( is_search() || is_home() ) :  ?>

You just have to make sure that you don’t include the

is_category()

and you’re all set.

True, you could further optimize this in a way that you would show excerpts for all other categories except “codeproject”.

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);
Books

Choose Yourself! – James Altucher

My notes from the book Choose Yourself! by James Altucher:

Learned man aims for more, but the wise man decreases, and then decreases again.

The thing that really matters in this world are relationships you have with people you love and meaningful things that you do. Haters don’t fit anywhere into that.

  • Sleep eight hours
  • Eat two meals instead of three (I don’t agree with this one personally smileyGlasses)
  • No TV
  • No junk food
  • No complaining for one whole day
  • No gossip
  • Return an email from five years ago
  • Express thanks to a friend
  • Watch a funny movie
  • List down a bunch of ideas
  • Read spiritual text
  • Say to yourself in the morning “I’m going to save a life today”
  • Pick up a hobby
  • Surprise someone
  • Think about five people you’re grateful for
  • Forgive someone – write it on a paper and burn it
  • Take the stairs
  • Don’t see yes when you think no
  • Tell someone you love them
  • Deep breathing

After a certain salary point, your marginal happiness doesn’t go up.

Writing a book never really makes a lot of money, but there are all these additional benefits of writing a book: consulting, speaking, TV shows, ghost writing, email list to market further. 

In order to get good ideas read two hours a day and write ten ideas a day.

Wake up and think of five people you’re grateful for.

Meditation – don’t time travel, be in the present.

Negotiation is worthless, sales is everything.

Better to sell early than to go broke.

Simple effort will give you a customer for life – always give a little extra. 

If you love something you get knowledge, the contacts, you’ll build something nobody else has, you’ll wow the customers.

… and that’s Stephen King – all it took was a few weeks of not writing to fall completely off his game even though he’s one of the best in the world at what he does.

The idea muscle has to be exercised daily.

Activate another part of your brain. Best ideas come from collision between  newer  and older ideas. Take two older, unrelated ideas and make them have sex.

Perfectionism may harm you. Embrace failure and get ASAP on your feet again.

Delegate jobs to someone else.

If you can’t help yourself you won’t be able to help others.

Be physically, emotionally, spiritually and mentally healthy.

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

Quick tips

How to add a subdomain for Nodejs application on DigitalOcean

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) but that they would be accessible from different domains (for example mean.nikola-dev.com). Below are the steps I needed to take in order to make this happen:

  1. Clearly, have a droplet on DigitalOcean
  2. Buy a domain (where ever you buy it, make sure you use Honey, to get the best price)
  3. 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
  4. Add the domain on DigitalOcean DNS settings page:
    digitalOcean_dns
  5. Delete /etc/nginx/sites-enabled/default
  6. 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;
    }
  7. 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;
        }
    }
  8. Restart NGINX:
    sudo service nginx restart

Clearly, if you would need to add more subdomains, just repeat the steps from step 6 onward. Of course, you would need to put your other Node.js apps on different ports, since only one app can work on one port.

Books

EDGY Conversations – Dan Waldschmidt

My notes from an awesome book EDGY Conversations by Dan Waldschmidt, which I rated 5/5 on my Shelfari account:

Success is not about what you do, it’s about what you are.

Who and what do you want to be, and why?

Van Gogh sold only one picture during his lifetime.

You have to look within yourself and challenge the demons that hold you back from being successful.

You’ll never rise to be a champion if you can’t pass the fear and the failure and the excuses holding you back.

You have to believe that you can be amazing regardless of where or who you are right now.

Carl Sugarfoot Joseph

Simply getting up one hour earlier a day for 50 years equates to an extra 2281 business days, or 6.25 years of conquest.

You win more when you fight more.

Success is an attitude: don’t be afraid to be extreme, be disciplined, be giving, understand the why human factor.

Are you willing to commit to extreme behavior? When you decide that it’s going to be hard. When you know that you have to outwork, outthink, outplay, outmuscle everything you do from this day forward extreme behavior actually becomes a great way to focus what you do.

Small jump forward is actually a big leap backwards.

You want harmony, not balance.

People really want to believe effort is a myth. I think we’ve been tricked by the few lucky people on the top of the heap. We see the folks who managed to get by and it’s easy to forget that these guys are the exceptions. For everyone else effort is directly related to success. You don’t get to choose luck, effort on the other hand is available there all the time.

Jerry Rice

Only limits that exist are the ones in your head.

With discipline and effort you can do just about anything.

The average age of a successful interpreter is mid 40s.

Effort is more than ‘if you pay me more, I’ll work harder’, it’s about not cheating yourself out of your potential.

Cliff Young

Passion is the antidote to the setbacks you will surely face on the way to success. It’s that often illogical passion and emotion that allows you to keep going long after it makes sense. When you put enough of yourself into something you will do whatever it takes to come out as a winner.

Anyone can conquer when the odds are in their favor. The challenge is to do what it’s hard and the noble and the right when you are sick and tired and tired and sick.

It takes discipline to keep moving forward.

It’s not only what you’re willing to do what will make you successful, it’s also what you’re willing to do without, until you get there.

You may spend a decade of sleepless nights until you make it to the finish line – and you need to plan for that.

Plan to work harder than you ever imagined possible. And then, double that effort!

Your plan should be bigger than simply “not losing”.

Have a giving mindset.

Success and living in balance life should not be in the same sentence.

Give expecting nothing in return, and you will change people’s lives.

Marianne Williamson: “Our deepest fear is not that we are inadequate. Our deepest fear is that we are powerful beyond measure. It is our light, not our darkness, that most frightens us. We ask ourselves, who am I to be brilliant, gorgeous, talented, fabulous? Actually, who are you not to be? You are a child of God. Your playing small doesn’t serve the world. There’s nothing enlightened about shrinking so that other people won’t feel insecure around you. We are all meant to shine, as children do. We were born to make manifest the glory of God that is within us. It’s not just in some of us; it’s in everyone. And as we let our own light shine, we unconsciously give other people permission to do the same. As we’re liberated from our own fear, our presence automatically liberates others.”

Derek Redmond

Brain handling new information: If it’s boring or expected, brain ignores it. If it’s too complex, the brain dramatically summarizes it. If it’s threatening it prepares for “fight or flight” scenario.

What do you think about most is what you become. You are today who you thought you would be. You will be in the future who you think you want to be today.

Everything in life starts with your thinking. If you let fear drive your thoughts, you’ll never do the things that lead to success. You’re actually a lot stronger than the fear in your mind lets you think you are.

If you want to dominate, control your thoughts.

Successes is what you decide it is, not what other people tell you it should be. You decide what is right for you.

You,  believe in you…

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).

Miscellaneou$

My new Lenovo Apple laptop with a custom hood

Update: Before I got rid of the Lenovo laptop, it looked like this:

lenovoFinal

TL;DR: Stickers can be seen here on StickerMule. If you happen to signup up via this link, you’ll get 10$ off of your next purchase. Thank me later… hand_rock_n_roll

Ok, ok, so before you start jumping about the title for thinking how did I not know about Apple buying Lenovo, and start calling your wallstreet woolf to get you a deal on some Apple stocks before they skyrocket again, let me calm you down by saying it’s just the stickers, it’s just the stickers 😉

So, as you may know I’m pretty much into Ionic framework lately and I stumbled upon some Ionic stickers on StickerMule and added them to cart immediately.

Then, I browsed through the site and as it seemed they offer you to upload your own stickers. So, I contacted their support team, and boy can I tell you their response time was fast. Like, super fast. They told me the details about the sizes and image quality in order for it to look good when printed.

Since I very much like MEAN stack and there were no stickers for it available yet, I made my own and you can take a look at them here on StickerMule.

I also ordered the sample pack for just 1$. The shipping price via air mail to Croatia was about 6$, but I have to say the shipping was indeed fast (less than a week, which to our country is, trust me I’m lying, fast).

The quality of the stickers is very good, and I like the personal touch where the person who packaged the stickers signed it by hand (see the image below).

Here are some pictures of the arrived lot:

IMG_4186 IMG_4189

Here’s the signature of the person who packaged it – thanks Wendy! IMG_4216

Here’s how my laptop now looks from the inside :). Yes, keep calm folks, I use R.A.T 7 and drink too much coffee too.

IMG_4218

And here’s how it looks from the outside. Before I only had the Apple logo in the middle (yeah, I happen to like Apple products, sue me smileyGlasses – erm, so why Lenovo then? Ah, that’s another story, ping me on mail or comments if you’re really intrigued). The blank space on the right hand side is left for a new sticker that’s coming soon 🙂

IMG_4219

Anyways, StickerMule has my recommendation for being awesome when it comes to stickers!

Page 33 of 52« First...102030«32333435»4050...Last »

Recent posts

  • Vibe Coding a Pokémon Search App with Replit
  • SendGrid Phishing Scam Attempts
  • Retrospective Questions
  • When espanso Breaks on Long Replacement Strings (and How to Fix It)
  • 2024 Top Author on dev.to

Categories

  • Android (3)
  • Books (114)
    • Programming (22)
  • CodeProject (36)
  • Daily Thoughts (78)
  • Go (3)
  • iOS (5)
  • JavaScript (128)
    • Angular (4)
    • Angular 2 (3)
    • Ionic (61)
    • Ionic2 (2)
    • Ionic3 (8)
    • MEAN (3)
    • NodeJS (27)
    • Phaser (1)
    • React (1)
    • Three.js (1)
    • Vue.js (3)
  • Leadership (1)
  • Meetups (8)
  • Miscellaneou$ (80)
    • Breaking News (8)
    • CodeSchool (2)
    • Hacker Games (3)
    • Pluralsight (7)
    • Projects (2)
    • Sublime Text (2)
  • PHP (6)
  • Quick tips (41)
  • Servers (8)
    • Heroku (1)
    • Linux (3)
  • Stack Overflow (81)
  • Unity3D (9)
  • VibeCoding (1)
  • 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