Quantcast
Channel: Devdactic – Ionic Tutorials
Viewing all 183 articles
Browse latest View live

5 Reasons Why You Should Blog as a Software Developer

$
0
0

Blogging has become way more than a little hobby. Blogging offers great possibilities you can find nowhere else. Especially in the software development area it’s pretty hard to stand out given the amount of great developers around the world.

In this post I will share my experience on blogging and how your life and job can benefit from blogging. If you already have a blog, I would be happy if you leave a comment below to share your own results with others!

1. Show your Skills and Expertise

Having a blog means presenting your skills and knowledge to the world. This isn’t always easy.

If you think “I am such a beginner, everyone knows more than me” than just stop that thought, because it’s completely not true. When I started, I was just learning this and that about the Ionic Framework and 2 months later I had a guest post on the official Ionic blog.

Have I been an expert at that point? Hell no.

But I was interested and had the courage to just ask them. They are looking for people just like you!

A short time later I submitted a post to a writing contest, and I made the 3. place in the whole competition.
airpair-competition-winners
Again, I was by no means an expert! Just go out and show your skills, and people will be thankful that you share your knowledge.

So these little success were great, but don’t directly affect your job.
What can affect your job is what others can see and read about you online. A solid Github account, apps in the Appstore or a coding blog help you to more easily show your skills to recruiters. If they see what effort you put into helping and learning new tools, you are well on the way to become successful.

I hope you get the point: To Blog as a Software Developer can affect your career and opportunities only in positive ways. Showing your skills these days is the most powerful instrument to get a new job or raise.

2. Learn new Technologies and Soft Skills

Since I started this blog, I have learned various new technologies and frameworks, just because I want to present them to my readers. As a developer, you should have a natural interest in learning new skills, just to stay on top of the game.

“Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young.” – Henry Ford

Being at the edge of technology is so much fun while also challenging. You have to deal with problems no one ever had, which builds up your own skills to solve problems and also increases your arsenal of tools.

yeomanFancy Yeoman stuff
Having encountered and learn new technologies online allows you to promote them where you work. You get a bigger picture of the current technologies and become in general a more “fullstack” developer.

But to Blog as a Software Developer is not only about learning new technology stacks and languages, it’s also about learning completely new skills: Marketing yourself as a Developer.

A great resource on why you need to market yourself comes from John Somnez, who is sharing all kinds of strategies and advice on his own blog. If you are not sure why this is relevant, just check out some links on his blog.

Why sou should market yourself?

Simply having more opportunities as a Developer.

3. Get a deeper understanding by Teaching

So far the reasons I discussed were mainly related to your job, opportunities or career. This one is more about your skills in general.

If you follow tutorials, use code from Stackoverflow and so on you merely touch learning something. You might get better by repeating, but you will not completely understand what you are doing.

Writing a blog post about a topic or even a tutorial challenges you.

You need to understand what you do, to write and teach to others. You won’t find any words if you have no idea what you are doing!

Have you ever explained something to a colleague?
You can only do this if you understand what you are talking about. Same counts for blogging.

By regularly exploring, learning and teaching you increase your knowledge about languages and frameworks in an unbelievable great way. What you teach once won’t be forgotten so fast!


What you teach once won’t be forgotten so fast!
Click To Tweet


4. Build relations with other developers

The life of a Software developer can be a bit lonely sometimes, especially if you work remotely.
But also only knowing some fellow developers sometimes doesn’t mean you have good relations with them.

While I never thought that blogging would really result in new connections, I must admit: it does.

Connecting with other bloggers helps to grow your blog, but it’s even better to talk to someone who does something like you. I was lucky to get in contact with the great Nic Raboy who is a great developer teaching stuff just like me. We are constantly chatting about blogging stuff and I really feel connected with him. He was also the one who accepted my first guest post, so at this point: Thank you Nic, would love to meet you if I come to the USA one day!

There are many more people out there, including not only bloggers both tech guys from great frameworks.

Just having a blog opens the magical doors to talk to all kind of other bloggers to share your thoughts with. You could also do this without a blog, but starting the conversation with a reference to yours and his blog somehow breaks the ice.

Why you want connections?
Having real connections can help you, offer you support when times get hard and just feel great in a more and more cold world. Thanks to all the great fellow bloggers I have talked to until now, hope to get to know even more!

5. Expand your blog to your own business

Finally, blogging can lead to great business opportunities.

And I have built up all of this in a year while working a fulltime job, 40 hour workweek and 2 hour commute every day. No excuses!

Once you have your own blog up and running for a while, you can expand into all directions. You can create your own products, write books and sell them, or offer your own services.

If you are a freelancer, you can attract new customers just by showing your skill and also including your portfolio (which would also be recommended for employees hoping to find a new job). The possibilities are countless.

By having an audience you can validate your own ideas for building new products or tools, support and market the stuff you have already created.

You can also make a lot of money from blogging, but I won’t cover all the techniques for that in this post. If you are interested in these things, leave me a comment or tweet me!

How blogging can affect your life and career

Blogging as a Software Developer is an amazing way to increase your personality. Whatever you plan to do, a Blog can boost whatever you do. It opens doors where you would never expect them.

If you would like to see more content about blogging and online business, leave me a comment below and tell me what you are interested in!

Hope to hear from you,
Simon

The post 5 Reasons Why You Should Blog as a Software Developer appeared first on Devdactic.


How to call REST API and Parse JSON with Swift 2.2

$
0
0

When we talk about how to parse JSON with Swift we think about dictionaries and ugly code getting to the values of a REST API response. This processs can be made a lot cleaner and structured using a simple library and a REST response wrapper class.

Some time ago I had the post How to Make REST API Calls and Parse JSON with Swift, which was for an older Swift version and also using an older SwiftyJSON implementation. Today I will show you how to parse JSON with Swift 2.2 using SwiftyJSON through cocoapods and the Randomuser API for a dummy JSON response.

Setup the app and cocoapods

We start with a clean App so start Xcode, go ahead and Create a new Project and select the Single View Application. Insert your credentials and whatever name you like and finish the process.

As said before, this time we will use cocoapods which is a dependency manager for iOS libraries to install a pod called SwiftyJSON. This library helps us to parse JSON with Swift a lot easier.

To install cocoapods, follow the instruction on the official cocoapods website. Afterwards, create a Podfile at the rot of your blank project and insert:

platform :ios, '8.0'
use_frameworks!

target 'devdactic-rest' do
  pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git'
end

This is a very simple Podfile, we just specify the target name (which was in my case devdacti-rest) and the Pod we want to install plus the git source. Save this file and run pod install from your command line.

If this finishes successful, please use the *.workspace file from now on as this includes your original target and the Pods target.

Note: We have to specify use_frameworks! in our Podfile because SwiftyJSON is a Swift Pod.

If you want all of the code of this tutorial, grab your complete package below!


The final app with some dummy data will look like this:

parse-json-with-swift

Creating our REST Connection Manager

I love having all of my REST calls in one place, so inside your project create a new Swift file called RestApiManager.

In this class we will talk to the Randomuser API and see how to perform a simple GET and POST request with Swift. Open your created file and insert:

import SwiftyJSON

typealias ServiceResponse = (JSON, NSError?) -> Void

class RestApiManager: NSObject {
    static let sharedInstance = RestApiManager()

    let baseURL = "http://api.randomuser.me/"

    func getRandomUser(onCompletion: (JSON) -> Void) {
        let route = baseURL
        makeHTTPGetRequest(route, onCompletion: { json, err in
            onCompletion(json as JSON)
        })
    }

    // MARK: Perform a GET Request
    private func makeHTTPGetRequest(path: String, onCompletion: ServiceResponse) {
        let request = NSMutableURLRequest(URL: NSURL(string: path)!)

        let session = NSURLSession.sharedSession()

        let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
            if let jsonData = data {
                let json:JSON = JSON(data: jsonData)
                onCompletion(json, error)
            } else {
                onCompletion(nil, error)
            }
        })
        task.resume()
    }

    // MARK: Perform a POST Request
    private func makeHTTPPostRequest(path: String, body: [String: AnyObject], onCompletion: ServiceResponse) {
        let request = NSMutableURLRequest(URL: NSURL(string: path)!)

        // Set the method to POST
        request.HTTPMethod = "POST"

        do {
            // Set the POST body for the request
            let jsonBody = try NSJSONSerialization.dataWithJSONObject(body, options: .PrettyPrinted)
            request.HTTPBody = jsonBody
            let session = NSURLSession.sharedSession()

            let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
                if let jsonData = data {
                    let json:JSON = JSON(data: jsonData)
                    onCompletion(json, nil)
                } else {
                    onCompletion(nil, error)
                }
            })
            task.resume()
        } catch {
            // Create your personal error
            onCompletion(nil, nil)
        }
    }
}

As we only want to expose the functions we need, we make our GET and POST request methods private.

We also define a typealias for all of our responses, which will always consist of the JSON object and an optional NSError.

There is nothing really special in here, we just make plain HTTP calls and can pass the data object directly into the initializer of SwiftyJSON.

If you have any questions to the implementation of the REST Manager, please leave a comment below!

Parse JSON with Swift

Now that we got the backbone of our app, we take care of the View. But before we actually craft the final view, we create a wrapper for our REST response. To parse JSON with Swift we could only rely on SwiftyJSON, which makes life already a lot easier.

To get to a stage of even better understandable code I recommend to create wrappers for your responses. By doing this you only have to access values by their name once in the init of the object. This means, if anything changes from the backend side, you only have to change it in one location in your app.

This can save a big amount of time in big projects, plus using the objects from then on is a lot friendly for everyone reading and working with your code.

So enough words, create a UserObject Swift file and insert:

import SwiftyJSON

class UserObject {
    var pictureURL: String!
    var username: String!
    
    required init(json: JSON) {
        pictureURL = json["picture"]["medium"].stringValue
        username = json["email"].stringValue
    }
}

The values we access can be seen in the response of the Randomuser API, for now we just use the name and an image. Let’s see how to create our user objects from our controller.

UPDATE: We need to use the “email” field now as the “name” field seems to be empty.

Inside your project you should already have a quite empty ViewController, so we can use that one for our tableView.

We want to display all the users we receive from the API inside a simple UITableView. Additionaly we want to have a little button to reload more users into our list. A POST request would have no effect on the Randomuser API side, so we just focus on get and creating our objects now.

Open your ViewController and replace everything inside with:

import UIKit
import SwiftyJSON

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    var tableView: UITableView!
    var items = [UserObject]()

    override func viewWillAppear(animated: Bool) {
        let frame:CGRect = CGRect(x: 0, y: 100, width: self.view.frame.width, height: self.view.frame.height-100)
        self.tableView = UITableView(frame: frame)
        self.tableView.dataSource = self
        self.tableView.delegate = self
        self.view.addSubview(self.tableView)

        let btn = UIButton(frame: CGRect(x: 0, y: 25, width: self.view.frame.width, height: 50))
        btn.backgroundColor = UIColor.cyanColor()
        btn.setTitle("Add new Dummy", forState: UIControlState.Normal)
        btn.addTarget(self, action: "addDummyData", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(btn)
    }

    func addDummyData() {
        RestApiManager.sharedInstance.getRandomUser { (json: JSON) in
            if let results = json["results"].array {
                for entry in results {
                    self.items.append(UserObject(json: entry))
                }
                dispatch_async(dispatch_get_main_queue(),{
                    self.tableView.reloadData()
                })
            }
        }
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("CELL")

        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")
        }
        let user = self.items[indexPath.row]

        if let url = NSURL(string: user.pictureURL) {
            if let data = NSData(contentsOfURL: url) {
                cell?.imageView?.image = UIImage(data: data)
            }
        }
        cell!.textLabel?.text = user.username
        return cell!
    }
}

As you can see, a very straight forward UITableView with an items array for our users and a UIButton to call addDummyData.

Inside this function we call the singleton instance of our RestApiManager an use the JSON result as an array from which we create a new UserObject for each entry.

In only a few lines we have added a lot of logic and parsing and can now use the Object in the standard Swift way!

That’s what I really like about doing it this way. If you look at the cellForRowAtIndexPath function, you see how easy we can access the name and image of a user now, plus some if let logic to only load data into an image that really exists.

Now go ahead an run your app!

UPDATE: If you encounter “Transport Security Has Blocked a cleartext http….” which you will for sure, you should edit your .plist file and add App Transport Security Settings and under App Transport Security Settings set Allow Arbitrary Loads to Yes.

See how in this Stackoverflow post.

Thanks again to Jasper for reporting this!

Conclusion

JSON parsing with Swift can be quite easy using the right approach. In general you don’t want to access the variables inside the JSON often by using the string names, that’s why it’s a good approach to seperate this logic into wrapper classes or structs you can use after creating the initial object from JSON!

If you want to see some real JSON parsing in action, check out my online course Swift in Action: Building Realtime iOS Apps with Firebase!

Happy Coding,
Simon

The post How to call REST API and Parse JSON with Swift 2.2 appeared first on Devdactic.

The Complete Ionic Push Notifications Guide

$
0
0

Ionic Push Notifications, once again. My previous articles on this topic had the most comments and questions ever, so as the way of using this has changed again a bit to the current Beta status, we will put everything from starting with dummy push notifications to real iOS and Android push notifications inside this article.

This guide aims to help you set up push notifications for your Ionic app. Also I will append new questions to the final help section for something like the FAQ of Ionic push notifications. Without more words, let’s start the fun.

It’s going to be a wild ride!

Oh and if you want to grab a Postman collection with all the HTTP Requests you need for creating and observing Push notifications, just enter you email below!

Start the smallest Push App ever

The funny thing here is that we actually need almost no code for push to work. Anyway, we start with a blank Ionic app and add 2 plugins, the ionic-platform-web-client which will handle the connection to Ionic.io and the phonegap-plugin-push which handles incoming pushes inside your app (and how you want to react upon receiving them). So go ahead and run:

ionic start devdactic-push blank
cd devdactic-push
ionic add ionic-platform-web-client
ionic plugin add phonegap-plugin-push --variable SENDER_ID="GCM_PROJECT_NUMBER"

We need a GCM project number for our Android app, but as we currently haven’t created something like this you can simply add it with the dummy string, or leave the part with –variable.. out for now.

When I installed the plugin I got this error:

Plugin doesn’t support this project’s cordova-ios version. cordova-ios: 3.8.0, failed version requirement: >=4.0.0

If you encounter this as well, here is the fix to install the right iOS platform:

ionic platform rm ios
ionic platform add ios@4.1.0

Alright, the basic is done, let’s connect our app to the Ionic.io services!

If you have no account there, now is the time. It’s free and you need it in order to send Ionic push notifications to your app.

Your account is ready?

Then continue on your command line and run:

ionic io init
ionic config set dev_push true

First of all this will create an app id inside your Ioni.io dashboard, and we also enable Dev Pushes for our app to test if everything works until now. The name Dev Push is not really good and afaik they think about changing it to to Demo Push, hope we see that change soon!

The funny part is now the code we actually need. Open up your app.js and replace the current .run() block with this:

angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    var push = new Ionic.Push({
      "debug": true
    });

    push.register(function(token) {
      console.log("My Device token:",token.token);
      push.saveToken(token);  // persist the token in the Ionic Platform
    });
  });
})

We could actually leave out more lines, but I think this is fine for now. We create a new Push object and register ourself. On success, we will log our device token which we need to send push notifications to.

And that’s everything we need right now, so let’s see our app in action.

Creating Ionic Demo Push Notifications

To test our app we want to use the Dev Push, but before we need to add a security profile and create an API key inside Ionic.io so that we can contact the services from outside.

So go to your created App inside the Ionic.io dashboard, click on Settings and in the submenu Certificates. We need to create a profile now, otherwise for me the push was not recognized (although it should work without a profile in this step, and previously did).

Anyway, we need this profile later for our iOS and Android certificates so go ahead and add one right now. I named mine test and the result looks like this:
ionic-security-profile

As said before we also need an API key to talk to the Ionic.io services from outside, so now go to API Keys and create a New API Token in the upper section of the page.
ionic-api-token

Now we are already able to send our Dev Push, so go ahead and run your app with ionic serve or on a device, and observe the log for our Dev Token!

Now we can send a push using a CURL request, the 3 things you need to have are:

  • DEV_DEVICE_TOKEN: The one you copied from your apps log
  • PROFILE_NAME: The name of your security profile
  • API_TOKEN: The API token you created

Insert those values into the command below, run it and you should see a message coming up in your browser!

curl -X POST -H "Authorization: Bearer API_TOKEN" -H "Content-Type: application/json" -d '{
    "tokens": ["DEV_DEVICE_TOKEN"],
    "profile": "PROFILE_NAME",
    "notification": {
        "message": "This is my demo push!"
    }
}' "https://api.ionic.io/push/notifications"

If you want it a bit more comfortable, I can recommend making those request with Postman, an awesome tool for testing APIs. The calls inside Postman for creating a dev push would look like the following.

The Body section of our push:
postman-push-body

The Headers for our notification:
postman-push-header

Setting up Ionic Push Notifications Profiles

To use the platform specific services of Apple and Google we need to configure some profiles and stuff, but the integration within Ionic.io has really become a lot easier by now. So let’s take a closer look at both platforms (or pick just he one you need!).

iOS

The Ionic team offers a very detailed guide on how to create the profiles you need, so I recommend you stick completely to this documentation on iOS Push Profiles.

Also, to generate these certificates you need a Mac and also need to be part of the Apple Developer Program. If you just joined now, you might also need to set up your general iOS Build Profiles, but you don’t need this step if you have already previously created iOS apps.

After going through the Push guide you need to have your App Id from the Identifier you created inside your Apple profile. Copy that ID and open your config.xml and add your ID:

<widget id="YOU_APP_ID" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

This is important because now your build iOS app will also have that bundle ID, which it needs to receive our pushes.

The last thing for iOS you need now is to upload the needed certificate into your Ionic.io security profile. You might have already done this as a final step of the Ionic guide, so just make sure that inside your security profile the Push Notification Service is set up correctly like this:
ios-security-profile

Android

The setup for Android is even a bit easier, because the certificate-signing-provisioning stuff get’s a lot easier. For Android you need to be inside the Google Developers program, and you also need to set up some basic keys (if you have never created Android apps before) using this documentation from Ionic.

If you have already worked with Android apps before you can skip that step.

The next step is to create a Google API project inside your dashboard and enabling Google Cloud Messaging. As I can’t describe it any better, please follow the advise on Android Push Profiles from Ionic.

After going through this steps you should have already added the API Key to your Ionic.io security profile (if not do now) and the result should look like this:
android-security-profile

The last thing we need to change now is the GCM number for our
– set GCM number for your project phonegap-plugin-push which we installed in the beginning with a dummy value. To make sure everything works correctly I recommend you remove the plugin and add it again but now with your GCM_PROJECT_NUMBER (which you can find inside your Google Dashboard). Also you n eed to add the android platform if you haven’t done already.

ionic platform add android
ionic plugin rm phonegap-plugin-push
ionic plugin add phonegap-plugin-push --variable SENDER_ID="GCM_PROJECT_NUMBER"
ionic config set gcm_key 

Send Real Ionic Push Notifications

Everything until here was smooth sailing and not the real world (ok maybe the Apple certificates very a bit hard). It’s time to get real, so start on your command line and set our Dev Push to false:

ionic config set dev_push false


From now on, we can only test our real Android and iOS Push Notifications on a real device!

Also, in order to see that we got the push you currently need to close the app to get a notification because the Push inside an open app will be handled directly. If you app is closed you can see the little banner at the top, so that’s what we want to see if everything ins working.

iOS

For iOS I recommend you simply build the app using ionic build ios and afterwards open the Xcode project. Why?

Because we need the log message of our token. And I often had a hard time getting to the log using a different method than this.

So if you run your app, you should find your device token inside the log. With that, and all the information you already had before, you can create a Push using the CURL or Postman commands we already had in the beginning. The result should look like this on an iPhone:
ionic-ios-push

Android

Coming from a native iOS background, Android was a bit tricky for me, especially getting the device token.

So after running ionic build android you should find your APK inside platforms/android/build/outputs/apk/YOURAPP.apk.
If you connect your Android device to your computer, you can now run adb install PATH_TO_YOUR_APP and have the app directly on your device.

Finally, we also need the device token, so I opened the Android Device Monitor running just monitor from the command line.

Inside the logs (have fun filtering for the right logs of your app!) you can find the token after the app starts somewhere in the onRegistration block just like in the image below.

android-ddms-pushtoken

With that token, you can again perform the create push call using CURL or Postman and the result on Android looks like this (maybe cooler background on your device):

ionic-android-push

Ionic Push Notifications Help Section

Ok so there you have it, the complete setup guide for Ionic Push Notifcations. This last section is now meant to help with some general problems you might encounter along the way.

This section will be updated with new questions and problems you have!

Cordova Push Plugin Behaviour

If you want to change the behaviour of how a push is handled inside your app and what options you also have, check out the Github repo of the phonegap-plugin-push .

HTTP Error Codes

When you create your pushes and don’t receive anything on your device, you should always check the status of the created push using the UUID you get after making the POST. This helped me a lot to troubleshoot what was going on, and you can find a list for all the error codes inside the Ionic documentation.

Happy coding,
Simon

The post The Complete Ionic Push Notifications Guide appeared first on Devdactic.

Using Ionic 2 SqlStorage For a Simple Evernote Clone

$
0
0

It’s about time to see some Ionic 2 in action, right? Therefore I started my journey with a little Evernote light clone, which is a little app to write notes that shows you a lot of the new features that comes with Angular 2. Especially we can see how to use TypeScript, what components in Angular 2 mean and how to use page, provider and pipe.

Overall we will use Ionic 2 SqlStorage for storing data in our app while creating a tiny notes app.

Setting up a blank new app

New to Ionic 2? Check out my rapid results course Ionic 2 in One Hour!

As always we start with a blank app. Make sure you have installed the Ionic 2 beta following this guide!

We specify the blank template and also to create this project as Ionic 2 project plus TypeScript. I don’t want to go into detail about TypeScript, making a story short: I think it will be the future and how to write JavaScript code. So it’s a good idea to get used to the syntax already!

Now go to your command line and run:

ionic start devdactic-notes blank --v2 --ts
cd devdactic-notes
ionic g page NoteDetail
ionic g provider NoteService
ionic plugin add cordova-sqlite-storage

After creating the project we also use the new Ionic 2 CLI generator command to create a new page and a provider, which we will see in action later. This just helps us to easily create new files and add them to our project, very handy.

Finally we install the Cordova plugin for SqlStorage, which you need if you want to run the app on a real device later. Otherwise the SqlStorage will fall back using WebSQL which is not a complete safe place for us to store information as it can get cleaned.

After the basic setup create a folder and file at app/pipes/truncate.ts which we also need later on.

The last step now is to hook up the CSS of our HomePage into the app/theme/app.core.scss so open that file and add:

@import '../pages/home/home';
@import '../pages/note-detail/note-detail.scss';

That’s it for the basic setup. You should be able to run your app now like always, if you want take a look around and try to understand how Ionic 2 works. If you’re ready, let’s move on.

The basic use of Ionic 2 SqlStorage

We first of all start with the entry point of our app, so open the app/app.ts and insert:

import {App, Platform} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {HomePage} from './pages/home/home';
import {NoteService} from './providers/note-service/note-service';

@App({
  template: '<ion-nav [root]="rootPage"></ion-nav>',
  providers: [NoteService],
  config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
  rootPage: any = HomePage;

  constructor(platform: Platform) {
    platform.ready().then(() => {
      StatusBar.styleDefault();
    });
  }
}

We haven’t actually changed a lot here from what’s already in there. But what we did is import our NoteService, the service that will be a provider throughout the complete app for all interactions with our Ionic 2 SqlStorage. That is also the reason why we add it inside the @App annotation.

The rest of this class just bootstraps our application using a standard inline template and by tting our HomePage as the root of our app.

As already said, the most important class for all of our database interaction is the NoteService. This class will handle reading and writing operations, while also defining a little Note class at the top to wrap some values in one object. Pretty cool this TypeScript, right?

The functions mostl speak for themselves, so open the app/providers/note-servie/note-service.ts and insert:

import {Storage, SqlStorage} from 'ionic-angular';
import {Injectable} from 'angular2/core';

export class Note {
  title: string;
  text: string;
  id: number;
  constructor(title: string, text: string, id: number) {
    this.title = title;
    this.text = text;
    this.id = id;
  }
}

@Injectable()
export class NoteService {
  storage: Storage = null;

  // Init an empty DB if it does not exist by now!
  constructor() {
    this.storage = new Storage(SqlStorage);
    this.storage.query('CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, text TEXT)');
  }

  // Get all notes of our DB
  public getNotes() {
    return this.storage.query('SELECT * FROM notes');
  }

  // Save a new note to the DB
  public saveNote(note: Note) {
    let sql = 'INSERT INTO notes (title, text) VALUES (?,?)';
    return this.storage.query(sql, [note.title, note.text]);
  }

  // Update an existing note with a given ID
  public updateNote(note: Note) {
    let sql = 'UPDATE notes SET title = \"' + note.title + '\", text = \"' + note.text + '\" WHERE id = \"' + note.id + '\"';
    this.storage.query(sql);
  }

  // Remoe a not with a given ID
  public removeNote(note: Note) {
    let sql = 'DELETE FROM notes WHERE id = \"' + note.id + '\"';
    this.storage.query(sql);
  }
}

Inside our constructor we create a new table inside our database if it doesn’t exist, and our variable storage holds the reference to that database.

All of the other functions simply perform an SQL statement on our SqlStorage and return the result (sometimes).

Any questions up to this point?

The List for our Notes

So now we want to actually use our service, and the first page our user sees is the HomePage.

Inside this class we import the NoteService, the Note class, our DetailsPage which will be pushed once we create a new note or if we select a note, and finally also a pipe called Truncate.

A pipe is pretty similar to an Angular 1 directive, and we will see it in action inside our view later. Again, we have to add this pipe inside the @Page annotation to use it later.

The array of notes inside our class will be filled through loadNotes, which is called onPageDidEnter so every time we come to this page. If you haven’t opened it by now, open the app/pages/home/home.ts and insert:

import {Page, NavController} from 'ionic-angular';
import {NoteService, Note} from '../../providers/note-service/note-service';
import {NoteDetailPage} from '../note-detail/note-detail';
import {Truncate} from '../../pipes/truncate';

@Page({
  templateUrl: 'build/pages/home/home.html',
  pipes: [Truncate]
})

export class HomePage {
  notes: Note[];

  constructor(public nav: NavController, public noteService: NoteService) {}

  // Initialise the notes by loading data from our DB
  private loadNotes() {
    this.notes = [];
    this.noteService.getNotes().then(
      data => {
        this.notes = [];
        if (data.res.rows.length > 0) {
          for (var i = 0; i < data.res.rows.length; i++) {
            let item = data.res.rows.item(i);
            this.notes.push(new Note(item.title, item.text, item.id));
          }
        }
      });
  }

  // Push the details page bute without an existing note
  public addNote() {
    this.nav.push(NoteDetailPage);
  }

  // Push the details page for our selected Note
  public noteSelected(item: Note) {
    this.nav.push(NoteDetailPage, {'note': item});
  }

  // Remove the note from the DB and our current arra
  public removeNote(note: Note) {
    this.noteService.removeNote(note);
    let index = this.notes.indexOf(note);

    if (index > -1) {
      this.notes.splice(index, 1);
    }
  }

  // Load our todos once the page appears
  private onPageDidEnter() {
    this.loadNotes();
  }
}

As you can see we load our notes through our service and create a new Note object for each entry we get back from the database. If we want to add a note, we simply push our DetailsPage which will then generate a blank new note.

But if we select a note, we push the DetailsPage and also pass the selected note as a parameter, so the page can then handle the rest for us.

Finally, deleting a note also happens through the function of our noteService, but we also want to actually remove the element from our current array of notes!

The according view to this class simply holds a list with all of our elements. On the top navbar we also have a plus button to create a new note, and every note entry has a sliding option button which can be revealed to remove a note.

The note element consists of the title and the text attribute of a Note object, and because the text can become a bit long we use our pipe here to limit the length of the string to 20. For now insert all of this in your app/pages/home/home.html:

<ion-navbar *navbar primary>
  <ion-title>
    My Notes
  </ion-title>
  <ion-buttons end>
    <button (click)="addNote()">
      <ion-icon name="add"></ion-icon>
    </button>
  </ion-buttons>
</ion-navbar>

<ion-content class="home">
  <ion-list>
    <ion-item-sliding  *ngFor="#item of notes" >
      <button ion-item (click)="noteSelected(item)">
        <ion-item-content>
          <h2>{{item.title}}</h2>
          <p>{{item.text | truncate: 20}}</p>
        </ion-item-content>
      </button>

      <ion-item-options>
        <button danger (click)="removeNote(item)"><ion-icon name="trash"></ion-icon> Delete</button>
      </ion-item-options>
    </ion-item-sliding>

  </ion-list>
</ion-content>

I think the view is pretty straight forward, we only need to get used to the new Angular 2 syntax.

The pipe we talked about all the time is also pretty easy to implement, we only have to code a transform function inside that class, so open app/pipes/truncate.ts and insert:

import {Pipe} from 'angular2/core';

@Pipe({
  name: 'truncate'
})

export class Truncate {
  transform(value: string, args: string[]) : string {
      let limit = parseInt(args[0]);
      return value.length > limit ? value.substring(0, limit) + '...' : value;
    }
}

As said before, we cut the string if it’s longer than the specified length (in our case we passed 20).

Many of these things might be new to you, but if you work with it for some days it will become your new standard (and you will get problems going back to Angular 1, have fun!).

So this is the first page, now we also need the DetailsPage to insert the actual note!

The detail view for Notes

app/pages/note-detail/note-detail.ts
We are almost finished, stay with me! This is the class now that get’s pushed onto our navigation stack with either a selected note as an argument or nothing.

Therefore, inside the constructor we try to get this Note from the navParams and set it as the current note. If we don’t get a note, we actually create an empty note right there and store this to our database.

Why?

This will create the ID for the note, so we have already a database entry which is empty but has a unique ID. This ID is used later when we update our note.

We will also always save our current note onPageWillUnload and in that cases show a little Toast message to our users, like in the image further down this side.

Now go ahead and open the app/pages/note-detail/note-detail.ts and insert:

import {Page, NavController, NavParams, Toast} from 'ionic-angular';
import {NoteService, Note} from '../../providers/note-service/note-service';

@Page({
  templateUrl: 'build/pages/note-detail/note-detail.html'
})

export class NoteDetailPage {
  note: Note = null;

  constructor(public nav: NavController, navParams: NavParams, public noteService: NoteService) {
    let passedNote = navParams.get('note');
    // Try to initialise our note for the page
    if (passedNote !== undefined) {
      this.note = passedNote;
    } else {
      this.note = new Note('', '', null);
      this.saveNote();
    }
  }

  // Save our note to the DB and show a message (optional)
  public saveNote(showBadge: boolean = false) {
    if (this.note.id === null) {
      this.noteService.saveNote(this.note).then((data) => {
        // Set the automatic created id to our note
        this.note.id = data.res["insertId"];
      });
    } else {
      this.noteService.updateNote(this.note);
    }
    if (showBadge) {
      let toast = Toast.create({
        message: 'Note saved',
        duration: 3000
      });
      this.nav.present(toast);
    }
  }

  // Called when this page is popped from the nav stack
  private onPageWillUnload() {
    this.saveNote(true);
  }
}

If you have any questions about this procedure, just let me know in the comments!

Finally, the view for this class again is pretty simple. We have our navbar at the top, and we have an input field for the title and also a textarea for our actual note.

If you want to use this in production, you need to have some automatic resizing of the textarea which is possible, but I won’t cover it here for now.
Open the app/pages/note-detail/note-detail.html and insert:

<ion-navbar *navbar primary>
  <ion-title>
    {{note.title}}
  </ion-title>
</ion-navbar>

<ion-content class="details">
  <ion-list>

    <ion-item>
      <ion-input type="text" value="" placeholder="My awesome note" [(ngModel)]="note.title"></ion-input>
    </ion-item>
  </ion-list>

  <textarea rows="15" placeholder="This will be awesome..." style="width: 100%; border: none;" [(ngModel)]="note.text">
  </textarea>

</ion-content>

That’s it! You can now run the app in your browser or device and should see an app like in the image below.

sqlstorage-preview

Conclusion

Get a kickstart to your Ionic 2 with my course Ionic 2 in One Hour!

It’s recommended to not use the localStorage with Angular 2 if you want to make sure your data is safe inside the app, so using the Ionic 2 SqlStorage is a pretty easy alternative. With some simple SQL statements you can get the complete power of SQL right inside your Hybrid app!

For a video version of this article, check out the screencast below!

Happy coding,
Simon

The post Using Ionic 2 SqlStorage For a Simple Evernote Clone appeared first on Devdactic.

10 Myths about Hybrid Development (and how to correct them)

$
0
0

“Hybrid apps are slow” was possible the first and most often heard argument I encountered when the discussion was about going hybrid instead of native. There was and sometimes still is an invisible barrier of ignorance.

Over the the years I heard or read many quite funny (but sad) arguments that most of the time came from pure ignorance.

This post aims to give you counter arguments for your next discussion.

When you hear one of these points from someone who has clearly just read one article about this topic which said native will always win, you got a chance to convince him to think twice.

1. Hybrid apps are slow

I think this is still one of the most used quotes.

Why does it exist?

Do you remember when Facebook decided that hybrid sucks and that they need to make it native? I think that was something everyone talked about.

Still you can hear the argument that Facebook switched because performance was bad. And yes, they had pretty good reasons to do this, because they are fucking Facebook. But the general app you will develop does not handle nearly the amount of data Facebook does.

hybrid-slow

Also, the beginnings of HTML webview apps were not as positive as everyone wished and hoped for. They thought “now we get 2 apps for the price of one”, but the other price they had to pay was performance. And many of these people failed some years ago and turned away from HTML5 apps for all time.

And now?

Let’s look at the true facts. Hybrid apps can be slow due to various reasons, but the main reason that influences performance is the device AND the software version which also means the browser. This is a big difference to native apps, so on old Android versions the performance can be really unusable.

But since Android 4.4 the browser is Chromium-based so you can rely on the HTML5 and CSS standards for browsers. Same counts for iOS, where every iOS version increase goes along with a massive increase of performance.

It’s true that you might not (by now) want to implement the next Vainglory using HTML, because these kind of apps rely on heave graphic rendering and should use the most bottom layer you can get to.

But for general apps, the reason of slow performance is becoming meaningless more and more, plus the webview performance will also increase all the time.

If you hear this reason again ask where the opinion comes from. You will for sure hear about the Facebook story again.

2. Hybrid apps look shitty

Another quite common phrase about hybrid apps. Often mentioned with the words “they will never feel native”.

But what really makes an app look good?

If you look around the Appstore ore Google Play Store, you will find a lot of apps that looks like your little 5 year old brother made the design. And many of them will also be native apps.

So the general design of an app lies in conception and creativity of the designer (or not if you are a one man show). And you can reproduce this design whether you use native elements or create your view completely with HTML and CSS.

And what if you can’t get as close to the design as you wish?

Well, in that case you can still use cordova plugins, which are are wrapper around some native functionality. That way you can stay inside your javascript world but still use the platforms native components.

So with more and more options on the webview, the design of a great view should be no problem at all by now. And if you want some examples of awesome looking hybrid apps, just take a look at these:

ionic-showcase

3. Hybrid apps are unsafe

This one came to me one fine day, and I really had to take a minute to think about it.

Why are hybrid apps more unsafe than regular apps?

I am still not completely sure about this, but I guess this fact came from thinking that using a webview inside an app and also using Javascript which tends to be evil sometimes would be easy to hack and unsafe.

Hybrid apps are as safe as you want them to be.


Hybrid apps are as safe as you want them to be.
Click To Tweet


Stick to the general rules and you can reach the same security level as native apps. Don’t store passwords in clear text on a device. Make HTTP requests over an SSL connection to be sure there happens no man in the middle attack.

Javascript code should always be obfuscated in production, which again reduces the risk of somebody hacking your code somehow.

And finally, your app runs in a container like always. Whether it’s native code or an webview performing some Javascript stuff, the security aspects and concerns are always more or less the same.

4. Build once, works everywhere

A very classic one, love it. Most of the time a sentence managers and people who only just heard about hybrid apps have in mind.

Have you ever heard this?

The image and idea of this is great, but it lacks reality.

When we think about using web technologies inside an app we hope to benefit from the lessons learned of web development. But in fact we just encounter more problems along the way.

Device fragmantation, screen sizes, power of those devices and different operating systems are just a starting point. On top we have different webbrowsers that sometimes shit on the CSS we define. Or just don’t know yet about that function.

Yes you will safe time to show it everywhere. But a 80% design solution on all devices is barely a solution given the level of most apps and expectations of users.

So if you hear this one again, just encounter with a better option of saying this: “build once, optimize everywhere“.

5. Building hybrid saves 50% of the development time

Very close related to the last one. And also quite as true as the last.

How often have you heard that one in a meeting?

Throwing up a cool number that sounds great is always effective for marketing, but when it actually comes to developing stuff, this number will change dramatically.

The general idea is pretty simple: Someone has read that you can create 2 apps (iOS + Android) with just one single codebase. The result is, that you obviously need 50% of the time you would normally need to develop 2 complete apps with 2 codebases!

Where is the problem with this?

Well, if you have ever developed a hybrid app you will most of the time test your code changes always in the same environment, for me it’s most of the time iOS because it’s faster. So you build your functionalities, views and everything looks great on my device.

Then I start it on Android and the app does by no means look or behave like it should. Why?

differences-hybrid

Those 2 systems behave different in so many ways. They use different browser engines which host our application. They use various screen sizes, densities and everything that potentially could break your layout. The cordova plugins to use the native functionalities might not work the same on both platforms. And the list goes on and on.

So yes you get a better maintainability, as far is your code is clean and structured. Future changes need to be made only once (but also with potential to be special for iOS/ Android).

But the result is definitely not 50% the time of developing 2 native apps.


Developing Hybrid Apps is hopefully 80% of the time of doing 2 native apps.
Click To Tweet


You got all the specialization for iOS and Android, you got a lot of unforeseen problems by doing everything with HTML and Javascript, you might need to tweak performance issues, and finally you might even write your own cordova plugins if there is no wrapper for the functionality you need.

All of these tasks take time, and for some it’s hard to predict how long it will take so you can have a huge risk factor in your calculation. This might even end up in doing 100%+ in time if you get stuck on some showstopper.

So if anyone again pulls up this number, decide whether you simply laugh and leave the room or maybe better) tell them the true facts about this myth.

6. If you want a five-star app, build natively

I think this one was from a forum, and the underlying assumption is: You can’t create a hybrid app that truly looks & feels native.

Is this true?

Well, some years ago I would have probably agreed with this. But technology evolves and most of the reasons for un-native behaviour can be eliminated using the right technology stack and coding guidelines.

Today, there are in fact so many apps that you won’t even recognise as hybrid, and many of them have great reviews. Just take a look at the Ionic Showcases to see some of them.

The thing is, this fact can become true if developers don’t know what they do and create the reason for bad performance or UI.

You can create bad hybrid apps today, yes. But you are responsible for that, not the technology!


You are responsible for good performance in hybrid apps, not the framework alone.
Click To Tweet


Also, if you think of a game like Vainglory, I have a really hard time imagining how this would look and feel using a hybrid technology. So as already said sometimes, if you rely on realtime 3D engines or stuff like that, I think it’s still better to do it native.

So in the end again, this myth is coming from a true case some years ago where you could clearly see if something was native or not. But today is different and you can blur the lines almost completely to produce an app that looks, acts and feels native although it’s a webview.

7. Just make our HTML5 website responsive and you got an app

The thoughts around this one seem to slightly shift today, but it’s still there some times.

This came up some years ago when everyone said they needed an app.

Why not simply make our website responsive and your ready?

Well… A responsive website on a mobile device and a hybrid app will most of the time be different pair of shoes.

It is true that a responsive website might look ok or even good if you throw it into an app container. But it’s still just a website, and people will feel it.

devdactic-website

A website has a very different UI concept then a mobile app, and there are slight differences that make an app look and feel great that you just don’t have on a website.

This comes from the fact that mobile devices have a lot smaller screens, so information and the flow of action has to be aligned to the size, the position of someones hand, what’s really important on the screen and so on.

It’s definitely recommend to have a responsive website, and this can also be the starting point for a hybrid app. But please, let some UX designer take a look at your app and ask them about comments.

In the end, and app is not always an app. If you don’t care about what the user thinks ok, but if you want a good feedback let the transition between OS and app be as smooth as possible, use the device functions and style guidelines for a platform.

This is the only way to transform a existing website into an app.

But most of the time I recommend it’s better to draw out the most important features of a website, reduce them, and focus on what the user really needs. Then craft a great app around that use-case and you are far better of.

8. “You won’t be able to implement this feature”

When it comes to talking about risk, this is an often brought up opinion.

Is it really impossible to implement some features or functions?

Yes and no. As said before, I would totally agree with this if you plan some graphic intense game with a lot of CPU usage. In that case, just go native.

But in all the other cases where you want to create a app even with native functions, there is a way to solve it using hybrid technologies.

There are already tons of great cordova plugins, and you can always feel free to create your own plugin if you need to! It’s not that hard.

So in fact, there is no real showstopper most of the time – but first of all experiencing problems with the way you could do it hybrid and then finding a solution using a cordova wrapper for some native code can take time.

This is a risk as well, and you should always estimate these points prior to the development of your app.

9. “performance was abysmal on older devices”

Let’s be honest, we all heard that one before, right?

It makes me kinda mad to counter this argument. But I try to keep calm.

First of all, there are 2 sides of the medallion: iOS and Android.

So for iOS, this problem does almost not exist. The performance even of older the devices is fair enough, and the fragmentation of the OS is so small that most of the time >90% will have the newest iOS version and therefore also a very good browser engine (where our hybrid app relies on).

You will barely experience any problems on iOS devices ever, so let’s keep those out of the discussion for now.

But as the image already indicates, for Android the landscape looks differently: A lot of different devices using any kind of OS version and often old stuff.

Why is that a problem?

Well, before Android 4.4 the browser engine was kinda bad and won’t get you good results. But everything newer will be better, and so do the capabilities of the devices increase. Like with iOS, you won’t experience problems with newer Android devices and versions.

Now another catch: You can bundle your own browser (Crosswalk) with Ionic Framework apps!

By doing this your app get’s a lot bigger, but you can be sure your app runs on a solid and stable base, which is enough to fix the problems we had some years ago.


Browsers, devices and our frameworks become better to easily overcome hybrid issues.
Click To Tweet


So while many people have experienced this myth, the truth is that it’s slowly disappearing. Browser, devices and also our languages and options get better to easily overcome these issues and make it a pure phrase in the future.

10. “hybrid still sucks. webview apps should all die.”

This last one is meant to be a bit funny. I read this response in a Reddit thread about my Airpair article Switching from native iOS to Android: Why Hybrid doesn’t suck (anymore).

Still, this case displays another group of people: Those that just hate everything besides native.

What is the problem of these people?

hybrid-apps-grandma

It’s hard to say, but the biggest reasons might be a) they have had really bad experiences with hybrid apps in the past or b) they just don’t want more people (all the web developers) to come into mobile development which was their own field for years now.

Either way, it will be very hard to convince this group and to have a serious discussion about facts. If you meet them in real live, just try to show them positive examples. And not all web developers will be mobile developers in the next years, the web is still important.

If this doesn’t work, just try to ignore them.

That’s the reasons I did not answer that comment on Reddit.

Final Words

Time’s have changed, so has technology. While hybrid is in some parts not on the level of native development, it already is in more then a lot areas. I am sure the battle native vs. hybrid and also vs. web will continue in the next years, but on whatever side you are just do your job good.

And stop flaming the other side, they are developers too.

If you want to try out something new, give hybrid a chance starting with the Ionic Framework.

Cheers,
Simon

The post 10 Myths about Hybrid Development (and how to correct them) appeared first on Devdactic.

Devdactic Challenge #1: Build a Calculator with Ionic

$
0
0

Today we start a new format on Devdactic called “Devdactic Challenge”, and this will be exactly what it looks like: A challenge for everyone around here to apply the learned skills and actually use them on real projects.

By starting to develop our own code and using the material we have read, we are much more likely to keep those things present and learn them for a long time. Therefore, this challenge aims to help you, give you little projects and the chance to become rapidly better at what you are doing.

FAQ

Types of Challenges

The series will start with Ionic Challenges, but it might evolve over time. If you have ideas for challenges, let me know them by email or Twitter! In general we will focus on mobile development and building great apps.

The Rules

The rules for the challenges are pretty easy. After I post the challenge, you can start to work on your solution for the challenge and upload your result to Github. Once you are done just send me the link to the Github repo!

If you don’t know how to use Git, this is a good point in time to get comfortable with it as well. You will need Git in your future career pretty much for sure. Anyway, it’s free to signup and you can have open repositories, so I can take a look at every submission.

You project also needs a little readme file telling everyone how to start the app (even if it’s only ‘ionic serve’)!

That brings us to the next point: For now I will pick the winner of the contest. I will take a look at the submitted solutions and announce the one who has done the best job in my eyes. If you are not the winner of a challenge, you can still get a lot out of it:

  • You apply skills in a real app
  • You can compare your solution to the winners solution
  • You can build up a Github repository which might become your future portfolio

So it’s a win-win-win situation for everyone around here! The challenges can be solved quite simple, but you can also put in more effort then needed if you just feel this helps you pushing forward.

After announcing the winner I also pull your app into a repository for this challenge series so all solutions and winners can be found in one place.

The Prize

With every challenge there will be little prizes. They will differ and I will announce the prize for every challenge individually. This is just a small incentive and additional benefit to what you already do for yourself and your career!

Open Questions

If you have any other questions or ideas, just leave them below this post! I am always open for constructive feedback and ideas.

Devdactic Challlenge #1: Build a Calculator

So let’s get to it, the first challenge!

You have to build a simple calculator using the Ionic Framework.

Sounds easy?

Well, here are some general features our calculator should have:

  • Numbers from 0 to 9 like a classic calculator
  • Add, subtract, divide, multiply
  • Field for equation and result
  • BONUS: If you feel like this was to easy, also add floating operations

You are free to pick Ionic 1 or 2, that’s completely up to you.

Also the UI can be made just as you want. Use only buttons, maybe use images, classic design or more modern approach. Whatever you like!

The winner of this challenge will get free access to my Ionic 2 in One Hour Course, his name will be announced here and I will also put the winning code into a Github repository which I will link here once we have a winner.

Deadline

The challenge is over.

The winner of this challenge is Pavel Hodek, you can find the winning app inside the repository that will later contain all winning apps.

Thanks for all the submissions, it was a pleasure to see you put in the effort and I hope everyone got something out of it!

Happy Coding,
Simon

The post Devdactic Challenge #1: Build a Calculator with Ionic appeared first on Devdactic.

How to Use Ionic 2 Firebase Integration For Cloud Sync and User Signup

$
0
0

Recently the Firebase platform got a complete redesign, including some new features and functions. As it’s still one of the most used cloud backends and with the soon to come Ionic 2 release candidate it’s about time to play around and build a little app using Ionic 2 Firebase Integration.

Good thing we have a great wrapper that makes life a lot easier: AngularFire2!

By using this library we can easily keep our data in sync with out cloud backend plus also easily embed authentication using email and password. Let’s find out how!

The Basic App and Firebase Setup

Before we start with the app, let’s create our Firebase app. Go to the new Firebase console and create a blank new project.

We need to copy some more strings from Firebase inside our app later, but we can actually find them directly on the overview page where it says “Add Firebase to your web app”. This is everything we will need for configuration.

Now it’s time for the Ionic app, so let’s start a new one including TypeScript and the AngularFire package:

ionic start devdactic-firebase blank --v2 --ts
cd devdactic-firebase
npm install angularfire2@2.0.0-beta.3-0930330 firebase@3.3.0 --save
typings install file:node_modules/angularfire2/firebase3.d.ts --save --global && typings install
ionic g page Login

Quick note: We use Ionic v2.0.0-beta.11 now!

This gives us a blank new Ionic 2 project including AngularFire and the Firebase lib. I specified those versions as there are currently many changes in all of those repositories. If you have problems after installing them, check out the complete template you can download at the top or leave a comment!

We also create a second LoginPage with the last command, which we will need soon.

Finally we get to the code, so let’s open the app/app.ts and insert:

import {Component} from "@angular/core";
import {Platform, ionicBootstrap} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {LoginPage} from './pages/login/login';

import {FIREBASE_PROVIDERS,
  defaultFirebase,
  AngularFire,
  AuthMethods,
  AuthProviders,
  firebaseAuthConfig} from 'angularfire2';

@Component({
  template: '<ion-nav [root]="rootPage"></ion-nav>'
})
export class MyApp {
  rootPage: any = LoginPage;

  constructor(platform: Platform) {
    platform.ready().then(() => {
      StatusBar.styleDefault();
    });
  }
}

 // Get he values from the overview page of your Firebase app
ionicBootstrap(MyApp, [FIREBASE_PROVIDERS,
  defaultFirebase({
    apiKey: "yourapikey",
    authDomain: "yourauthdomain",
    databaseURL: "yourdatabaseurl",
    storageBucket: "yourstoragebucket",
  })]);

As you can see we import a bunch of stuff from angularfire2, and in the provider section we can already configure it. Insert your Firebase URL here, it’s the only point where we ever need it!

The rest of this file is pretty straight forward, we only changed our initial Page to be the LoginPage which we have already created using the command line. Therefore we now need to work on our login view.

Building our Login

As said before, in this tutorial we will use a basic email and password authentication. This can be easily enabled inside Firebase, so go to your Dashboard and select your app. From the side menu navigate to Auth and find the point Sign in Method.

On that view we can enable all sort of logins, for now just make sure to turn the switch to on on the Email/Password card!

That’s everything we have to do from the Firebase side to enable authentication for our Ionic 2 with Firebase app.

We have previously generated our login page, so now go ahead and open app/pages/login/login.html and insert this:

<ion-header>
  <ion-navbar>
  <ion-title>
    Login
  </ion-title>
</ion-navbar>
</ion-header>

<ion-content padding>
  <form>
    <ion-item>
      <ion-label floating>Email</ion-label>
      <ion-input type="email" name="email" [(ngModel)]="user.email"></ion-input>
    </ion-item>

    <ion-item>
      <ion-label floating>Password</ion-label>
      <ion-input type="password" name="password" [(ngModel)]="user.password"></ion-input>
    </ion-item>

    <div padding>
      <button block (click)="login(l)">Login</button>
      <button block (click)="registerUser()">Create New Account</button>
    </div>
  </form>
</ion-content>

Nothing really special here, the only thing that might be new to you is the angular 2 style for a form. We actually don’t need any data model inside our controller for this, it’s all done on the fly!

Pretty cool, right?

So we got 2 actions, login with the inserted credentials or creating a new account from those. Both actions can be found inside our class for the Login, which is at app/pages/login/login.ts and which we edit now:

import {Component} from '@angular/core';
import {NavController, AlertController, LoadingController} from 'ionic-angular';
import {FirebaseAuth, AuthProviders, AuthMethods} from 'angularfire2';
import {HomePage} from '../home/home';

@Component({
  templateUrl: 'build/pages/login/login.html',
})
export class LoginPage {
  loader: any;
  user = {email: '', password: ''};

  constructor(public nav: NavController, public auth: FirebaseAuth, private alertCtrl: AlertController, private loadingCtrl: LoadingController) {}

  public registerUser() {
    this.showLoading()

    this.auth.createUser(this.user).then((authData) => {
      setTimeout(() => {
        this.loader.dismiss();
      });
      let prompt = this.alertCtrl.create({
        title: 'Success',
        subTitle: 'Your new Account was created!',
        buttons: ['OK']
      });
      prompt.present();
    }).catch((error) => {
      this.showError(error);
    });
  }

  public login() {
    this.showLoading()

    this.auth.login(this.user, {
      provider: AuthProviders.Password,
        method: AuthMethods.Password
    }).then((authData) => {
      this.loader.dismiss();
      this.nav.setRoot(HomePage);
    }).catch((error) => {
      this.showError(error);
    });
  }

  showLoading() {
    this.loader = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    this.loader.present();
  }

  showError(text) {
    setTimeout(() => {
      this.loader.dismiss();
    });

    let prompt = this.alertCtrl.create({
      title: 'Fail',
      subTitle: text,
      buttons: ['OK']
    });
    prompt.present();
  }
}

We import FirebaseAuth which allows us to use the auth property to create and login users. It’s really that simple!

If an account is successful created, we show a little success popup to the user.

If we login successful, we just set the rootPage of the navigation to the HomePage, which will basically be then the only view of our app.

Additionally we have an alert for errors and also a little loading indicator to show progress to the user. All of this done in really a few lines.

You can now go ahed and already test your user creation and login functions. They should be working by now, so if you encounter any error up to here leave a comment below. Otherwise let’s continue with our actual data list.

Cloud Sync Ionic 2 with Firebase

All of the previous stuff has been pretty easy – and it will continue like this.

The actual goal of using Firebase or a Backend as a Service is to have great sync between the data stored on that database and our app. To achieve this from our app we only need a few line,s but first of all we need to define our database structure on Firebase, so again go into your app and select Database.

In the following view click on the 3 dots at the right end of the card and select Import JSON, like in the image below.

firebase-database-import
Import JSON to Firebase as Database structure

For the JSON file, take this simple pre filled Database structure:

{
  "todoList" : {
    "0" : {
      "todo" : "My first Todo"
    },
    "1" : {
      "todo" : "My second Todo"
    },
    "2" : {
      "todo" : "My third Todo"
    }
  }
}

This JSON simply describes an array called todoList with 3 items in it. So after the import, you should already see 3 items inside the Firebase database for your app.


How to Use Ionic 2 With Firebase – Fullstack, Bitch!
Click To Tweet


We continue again on the app side (Fullstack, bitch!) to retrieve our new created list of todos. We start with the view for our list, so open the app/pages/home/home.html and insert:

<ion-header>
  <ion-navbar>
  <ion-title>
    My Todos
  </ion-title>
  <ion-buttons end>
    <button (click)="createTodo()">
      <ion-icon name="add"></ion-icon>
    </button>
  </ion-buttons>
</ion-navbar>
</ion-header>

<ion-content class="home">

  <ion-list>
    <ion-item-sliding *ngFor="let item of todoList | async">
      <button ion-item (click)="openTodo(item)">
        <ion-item-content>
          <h2>{{item.todo}}</h2>
        </ion-item-content>
      </button>

      <ion-item-options>
        <button danger (click)="removeTodo(item)"><ion-icon name="trash"></ion-icon> Delete</button>
      </ion-item-options>
    </ion-item-sliding>

  </ion-list>
</ion-content>

Inside our view we have a navbar, which will display an icon of the current user and also a plus icon for adding todos to our list.

The main content consists of a simple list that iterates over our todoList using the async pipe, which will automatically update our view once the array of Observable updates. Read more in the official documentation for AngularJS 2.

Our list item will then have the name of our todo, and also an option button which we can slide in where we can then remove the todo. Basic functionality, nothing special or new.

The more interesting stuff happens inside the Home class, so open the app/pages/home/home.ts and insert:

import {Page, NavController, AlertController} from 'ionic-angular';
import {FirebaseAuth, AngularFire, FirebaseListObservable} from 'angularfire2';
import {Component} from "@angular/core";

@Component({
  templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
  todoList: FirebaseListObservable<any>;

  constructor(public af: AngularFire, public auth: FirebaseAuth, public nav: NavController, private alertCtrl: AlertController) {}

  public createTodo() {
    this.editTodo(null, true);
  }

  public openTodo(todo) {
    this.editTodo(todo, false);
  }

  public removeTodo(item) {
    this.todoList.remove(item);
  }

  editTodo(todo, isNew: boolean) {
    let prompt = this.alertCtrl.create({
      title: isNew ? 'Create Todo' : 'Update Todo',
      inputs: [
        {
          name: 'title',
          placeholder: 'Title',
          value: todo ? todo.todo : ''
        },
      ],
      buttons: [
        {
          text: 'Cancel',
          role: 'cancel'
        },
        {
          text: todo ? 'Update' : 'Add',
          handler: data => {
            if (isNew) {
              this.todoList.push({'todo': data.title});
            } else {
              this.todoList.update(todo, {todo: data.title});
            }
          }
        }
      ]
    });
    prompt.present();
  }

  ngOnInit() {
    this.auth.subscribe((data) => {
      if (data) {
        this.todoList = this.af.database.list('/todoList');
      }
    })
  }
}

The start of the class happens at the end of the listing inside the ngOnInit, because after the page is initialised we subscribe to the auth status of angularFire.

Why?

Because our user needs to be really signed in to read the data! If we actually are signed in, we set our public todoList to this.af.list('/todoList') which will trigger our Firebase for an list of objects inside the todoList bucket!

This will also automatically update our list, as it’s of the type FirebaseListObservable.

To remove a todo from our list, we can simply call remove on our list, and everything will simply update in the background!

We have 2 events for opening or creating a todo, both do quite the same but when we edit a todo we need to gather the data we already have while we need to create a completely new entry if we select to add a todo.

Anyway, in the end there are only 2 functions that matter for those operations which are push and update, both can be simply called on our list with the object being the argument of the call.

Now run your app, watch the sync between your list and the Firebase database and simply feel awesome about what you did in nearly no time!

For a full video version this article watch the video below (and make sure to signup for my channel!)

Conclusion

I love the idea of having a backend database up in minutes, plus the ability to add social login features or special stuff like that in no time. The times are over where we would need an additional backend developer for a full blown backend – most of the time a simple BaaS can do the same or even better in a shorter amount of time and without big knowledge about complex backends. Working like this on front end backend just feels fast and good – Fullstack, Bitch!

Happy Coding,
Simon

The post How to Use Ionic 2 Firebase Integration For Cloud Sync and User Signup appeared first on Devdactic.

Devdactic Challenge #2: Build Tic Tac Toe with Ionic

$
0
0

The first challenge got great feedback on every channel, and I was more than happy to see some awesome submissions of people that applied their knowledge in this little calculator project. Today we continue with the second challenge and build Tic Tac Toe with Ionic.

If you don’t know what this challenge is about, go back to the rules (they are short) for a minute.

The general idea of the game is pretty simple, I guess everyone knows and has played it before. In case you need to go through the rules again check out the Wikipedia article for Tic-Tac-Toe.

Here are some features our final app should have:

  • Introduction view for new players
  • 3×3 board with fields people can check
  • AI for our opponent (can be very dumb/random)
  • Pause/Restart game
  • Check if someone has won the game after every turn

Compared to the Challenge #1 this challenge might have a bit less logic inside but we are developing a little game, so we want to have a clean UI that works on all devices. Therefore, put special effort into how you craft the view or game board, and stick to the Ionic grid system to create a flexible user interface!

As in challenge #1, you are free to use Ionic 1 or 2!

The winner of this challenge will get free access to my brand new Udemy course Blogging for Software Developers, which is the perfect fit for someone who is interested in increasing his skills and building an online portfolio of his skills and knowledge.

Deadline

The deadline for submissions is the Monday, 11. of July 2016. The winner will hopefully be announced in the week after.

If you like to submit your result, please send me an email or post a link to your Github repository with the solution below this post in the comments.

I’ll be waiting for you submissions here!

Even if you personally don’t want to participate, you would do me a great favour if you could share this article with your friends & colleagues!

Happy Coding,
Simon

The post Devdactic Challenge #2: Build Tic Tac Toe with Ionic appeared first on Devdactic.


NativeScript Angular 2 Introduction: Why NativeScript Matters

$
0
0

While there is a big buzz around Angular 2 and the Ionic Framework 2, a new force awakens in the shadow of the cross-platform development world. While this force has not yet reached the maturity level of other frameworks, the potential and the chances for success makes this force a worthy candidate to become one of the strongest frameworks on the cross-platform horizon.

The new force we are talking about is NativeScript, a framework to “Build truly native apps with JavaScript” as their page says.

Not another framework, cmon!

That was my first impression when my good friend Nic Raboy started to blog about NativeScript.

But some weeks ago on the German Developer Week conference I had the chance to sit down with the great Sebastian Witalec from the Telerik team, the creators of NativeScript. He gave me very good insight into what NativeScript is and what it isn’t, so today let’s explore what NativeScript can do for you!

What is NativeScript?

At the heart, NativeScript allows you to develop mobile apps from a single code base, written in JavaScript. With the release 2 you are now also able to use Angular 2 + TypeScript for your NativeScript apps, which is also one of the best ways to develop future web apps.

The great thing about it?

While Ionic 2 also uses Angular 2, the code of an Ionic 2 app is not completely the same like for an Angular 2 web app. With NativeScript, you code is actually very much the same, which gives you the chance to use shared code between your mobile and your web app. Pretty awesome!

We haven’t covered one of the most important parts about NativeScript yet: Native performance.

How?

NativeScript does not run in a Webview like Ionic or general cordova apps, but compiles to native UI components. The JavaScript for the logic is still packaged inside the app and not compiled to native code, but that’s not really a problem.

So in order to get native UI components on iOS and Android, NativeScript uses a special syntax for creating the views. This is not HTML, as it’s not running in a Webview (yeah Sebastian, I understand the reasons now!). The syntax for the view is like XML, but with Angular 2 support you can also use Angular 2 elements. It’s a bit confusing at this point and the documentation is not really good by now, but you will see it in action soon.

There is a lot more to say about the build system and other stuff related to NativeScript or the Telerik platform, but for now the knowledge is enough to dive into some hands-on stuff.

I am pretty new to NativeScript but wanted to give you the best possible impression, so like always we will develop a little app and see how it goes. Some people will like this way of doing things, others won’t and that’s fine.

No framework should target everyone, because that would in the end mean it won’t target anyone!

Let’s dive into some NativeScript code and build a little Pokéindex using the Pokémon API!

nativescript-pokemon

Starting a new NativeScript App

We start with an empty NativeScript app and pass the --ng flag to indicate we want to use Angular 2.

As the CLI is no that mighty at the moment, we need to create the folders and files we would like to have by hand, so feel free to copy the touch commands.

I’m using a Mac so I can add the iOS and Android platform, if you are not on a Mac you can only use Android!

// Install NativeScript if needed
npm install -g nativescript
//Create Project
tns create devdactic-pokemon --ng
cd devdactic-pokemon
tns platform add ios
tns platform add android
mkdir app/pages
mkdir app/pages/list
mkdir app/pages/pokemon
touch app/pages/list/list.component.ts
touch app/pages/list/list.component.html
touch app/pages/pokemon/pokemon.component.ts
touch app/pages/pokemon/pokemon.component.html
touch app/pages/pokemon/pokemon.component.css

If you want to run your app on iOS, you need to apply a little change to the app/shared_resources/info.plist to have access to outside APIs. This is also one of the strengths of NativeScript, you can actually change the behaviour or settings for one platform quite easily!

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

If you want to run this demo you need this in some form, NSAllowsArbitraryLoads in this example just allows all outside connections which might not be the best practice for productive apps. It was introduced with iOS9 and needs to be added because Apple wants to make sure you are using secure connections. Read more about it here.

By now your app should already work, so give it a try and run the app on whichever platform you like:

tns run android
tns run ios

// or inside the emulator
tns run android --emulator
tns run ios --emulator

As said before, the app does not run in a Webview so we can’t just debug the app inside Chrome like with Ionic. Anyway, NativeScript offers livereload to improve the development flow. This is a bit slow at the moment but speed improvements are planned for the next releases!

We also need to apply a little patch to our app in order to use HTTP requests. This counts only for the current version 2.2 of NativeScript and will hopefully be fixed soon.

So open the app/main.ts and insert:

// this import should be first in order to load some required settings (like globals and reflect-metadata)
import {nativeScriptBootstrap} from "nativescript-angular/application";
import {AppComponent, APP_ROUTER_PROVIDERS} from "./app.component";

// HACK - patch dom adapter
// For more info see: https://github.com/NativeScript/nativescript-angular/issues/305
import {Parse5DomAdapter} from '@angular/platform-server/src/parse5_adapter';
(<any>Parse5DomAdapter).prototype.getCookie = function (name) { return null; };

nativeScriptBootstrap(AppComponent, [APP_ROUTER_PROVIDERS]);

Setting up the Angular Router

Our app is currently empty, so let’s start with some logic for routing to our different views. As said before, NativeScript uses the actual Angular router.

Therefore, go ahead and open the app/app.component.ts and insert:

import {Component} from "@angular/core";
import {RouterConfig} from "@angular/router";
import {NS_ROUTER_DIRECTIVES, nsProvideRouter} from "nativescript-angular/router";

import {ListPage} from "./pages/list/list.component";
import {PokemonPage} from "./pages/pokemon/pokemon.component";

@Component({
    moduleId: module.id,
    selector: "my-app",
    directives: [NS_ROUTER_DIRECTIVES],
    template: `
      
        
      
    `
})
export class AppComponent {
}

export const APP_ROUTES: RouterConfig = [
  { path: "", component: ListPage },
  { path: "pokemon/:url", component: PokemonPage  }
];

export const APP_ROUTER_PROVIDERS = nsProvideRouter(
  APP_ROUTES,
  { enableTracing: false }
);

This looks a lot like Angular 2! We simply define 2 paths inside our app:

  • /list: The path to our ListPage, the default page we show after starting the app
  • /pokemon/:url: The details page for a specific Pokémon which is the PokemonPage

So this is the backbone of our app, let’s head on to the more interesting stuff!

Loading 150 Pokèmons inside a Listview

Because everyone knows that only the first 150 are the real Pokémon, we will simply load that amount from the PokéAPI.

Our ListPage loads the information and saves the data to an array, while also maintaining 2 loading states. These states are used for displaying a loading indicator and also fading in the list with the actual results.

Open the app/pages/list/list.component.ts and insert:

import { Component } from "@angular/core";
import { Http, HTTP_PROVIDERS } from '@angular/http';
import 'rxjs/add/operator/map';
import {Router} from "@angular/router";

@Component({
  selector: "list",
  providers: [HTTP_PROVIDERS],
  templateUrl: "pages/list/list.component.html"
})
export class ListPage {
  pokemon: Array = [];
  isLoading = false;
  listLoaded = false;

  constructor(private router: Router, private http: Http) {}

  ngOnInit() {
    this.isLoading = true;
    this.http.get("http://pokeapi.co/api/v2/pokemon?limit=150")
      .map(res => res.json())
      .subscribe((data) => {
        this.pokemon = data["results"];
      },
      (err) => {
        console.error(err);
        alert("Failed to load the data:" + JSON.stringify(err));
      },
      () => {
        this.isLoading = false;
        this.listLoaded = true;
      })
  }

  public showDetails(args: any) {
      let selectedPokemon = this.pokemon[args.index];
      this.router.navigate(["/pokemon", encodeURIComponent(selectedPokemon["url"]) ]);
  }
}

As you can see we also created the showDetails function which will be called once we want to drill down on a specific Pokémon of our list. We just need to get the selected object and then call the router and pass the URL for that Pokémon (the detail page will handle the rest of loading the new data).

So far everything looks like an Angular 2 app, but let’s see how the view is created.

Open the app/pages/list/list.component.html and fill in:

<ActionBar title="My Pokedex"></ActionBar>
<GridLayout>
  <Image src="http://pokeapi.co/media/sprites/pokemon/150.png" [class.hide]="!isLoading"></Image>

  <ListView [items]="pokemon" [class.visible]="listLoaded" class="small-spacing" (itemTap)="showDetails($event)">
    <template let-item="item" let-x="index">
      <DockLayout stretchLastChild="true">
          <Image 
            dock="left" 
            [src]="'http://pokeapi.co/media/sprites/pokemon/' + (x+1) + '.png'"
            width="45"></Image>
          <Label [text]="x+1 + '.  ' + item.name" class="medium-spacing"></Label>
      </DockLayout>
    </template>
  </ListView>
  <ActivityIndicator [busy]="isLoading" [visibility]="isLoading ? 'visible' : 'collapse'" row="1" horizontalAlignment="center"
    verticalAlignment="center"></ActivityIndicator>
</GridLayout>

This is no standard HTML in a *.html file! Dafack is this?

You just met NativeScript!

At first sight, this looks a bit strange. Always keep in mind that this view component hast to be rendered as native components, not a webview.

So what’s happening here is that we use a simple GridLayout Layout container from the NativeScript layout options. This allows us to easily add different view components and they get positioned like in a table with rows and views.

Additionally we style our rows with a DockLayout to show a little image of the Pokémon in front of our row. Most of the rest is simply Angular 2 syntax!

Everything in NativeScript lives in these layout containers, and once you get used to it this actually helps you a lot to build views faster. Also, great guys are currently working on rendering of NativeScript components inside the web. This could really be a huge help as you most of the time need an app plus a website.

Think about the view component what you want; it’s a bit irritating the first time coming from ionic and standard HTML, but it’s a pill you have to swallow if you want to go the NativeScript way.

What are your first impressions? Let me know below!

To get a better appearance effect and some styling for the list we add some styling and animation inside app/app.css (there are better places for styling, but this works as well):

.small-spacing {
  margin: 5;
}

.medium-spacing {
  margin: 10;
}

ListView {
  opacity: 0;
}

// Animations
.visible {
  animation-name: show;
  animation-duration: 1s;
}

@keyframes show {
  from { opacity: 0; }
  to { opacity: 1; }
}

.hide {
    animation-name: animate-hide;
    animation-duration: 2s;
    animation-fill-mode: forwards;
}

@keyframes animate-hide {
  from {  opacity: 1}
  to {  opacity: 0 }
}

These are actually standard CSS animations, which will be mapped to native changes of the UI like described in this post.

Basically we are defining some general properties in the upper half of the file and an animation to fade in or out our list view in the lower half using @keyframes to define the animation. By using the name of the animation inside the definition for animation-name the animation is bind to that property. If you want to find out more about NativeScript animations, check out their documentation for Animations with CSS.

Crafting the Details View for a Pokèmon

Let’s finish up our little app by adding the details view for a Pokémon. This component will get the URL to a specific Pokémon so it needs to load all the data for it at first.

Once we got the data, we grab some data out of the response, which is what we want to display (I know the real Pokédex was a lot cooler, but hey that’s up to you to continue this post!).

We also have some loading states again, just to have a better looking UI. So open the app/pages/pokemon/pokemon.component.ts and insert:

import { Component } from "@angular/core";
import { Http, HTTP_PROVIDERS } from '@angular/http';
import 'rxjs/add/operator/map';
import {Router, ActivatedRoute} from "@angular/router";

@Component({
  selector: "pokemon-page",
  providers: [HTTP_PROVIDERS],
  templateUrl: "pages/pokemon/pokemon.component.html"
})
export class PokemonPage {
  name: string = "";
  pokeimg: string = "";
  weight: number = 0;
  height: number = 0;

  isLoading: boolean = false;
  dataLoaded:boolean = false;

  constructor(private router: Router, private route: ActivatedRoute, private http: Http) {  }

  ngOnInit() {
    this.isLoading = true;

    this.route.params
      .map(params => decodeURIComponent(params['url']))
      .subscribe(url => {
        this.http.get(url)
        .map(res => res.json())
        .subscribe((data) => {
          this.name = data["name"];
          this.pokeimg = data["sprites"]["front_default"];
          this.weight = data["weight"];
          this.height= data["height"];
        },
        (err) => {
          console.error(err);
        },
        () => {
          this.isLoading = false;
          this.dataLoaded = true;
        })
    })
  }

  navigateBack() {
    this.router.navigate(["/"]);
  }
}

Again very standard Angular 2, not really much more we need to say about it. The map logic might look a bit strange but that’s how you get the most power in as few lines as possible.

The view inside the app/pages/pokemon/pokemon.component.html should contain this:

<ActionBar [title]="name">
  <NavigationButton text="Back" android.systemIcon="ic_menu_back" (tap)="navigateBack()"></NavigationButton>
</ActionBar>
<StackLayout class="item-group">
  <Label [text]="'Height:' + height" textWrap="true"></Label>
  <Label [text]="'Weight:' + weight" textWrap="true"></Label>
  <Image [src]="pokeimg"></Image>

  <ActivityIndicator
    [busy]="isLoading"
    [visibility]="isLoading ? 'visible' : 'collapse'"
    horizontalAlignment="center"
    verticalAlignment="center">
  </ActivityIndicator>
</StackLayout>

This time we use a StackLayout as container, which is simply arranging every object below the previous one. We want to have our Bar at the top to navigate back to the list, two labels with the information and finally the image.

I found it a bit complicated which syntax to actually use, so sometimes we access Angular properties but sometimes they are normal properties of the object. Also, the documentation is not very helpful at this moment, which was also noted by Raymond Camden when he worked with NativeScript. But I think the team is aware of this and will constantly improve this!

Finally, we can actually apply some styling to our not-really HTML view with some CSS inside app/pages/pokemon/pokemon.component.css so let’s do it:

.item-group {
    padding: 10;
}
 
.item-label {
    font-weight: bold;
}

That’s it for our first NativeScript app!

Now run your app on iOS or Android and enjoy your childhood memories of 150 Pokémon and their images.

nativescript-pokemon

Why NativeScript matters

As said before, my initial thoughts were “Why should I learn another framework?“, and still get those thoughts when working with new stuff like React Native.

But if you think a bit different everything becomes easier:

All of the frameworks for cross-platform development have their strengths and weaknesses!

For me there is no single best framework, it always depends on the business case and requirements you have. While Ionic is great in many areas, it will always be a Webview and you will always lack some performance vs. a native app.

There will always be people who don’t like Angular at all, which are better suited with something they might already know like Xamarin for .NET or React-Native for ReactJS developers, or even Unity3D if you want to target even more devices.

So we shouldn’t fight the cross-platform war like we fought Apple vs. Android, they both exist and you have to target both.


We shouldn’t fight the cross-platform war.
Click To Tweet


Back to NativeScript

So these were some general thoughts, now back to the question what makes NativeScript strong and who should use it?

First of all, every framework that settles on Angular 2 is a potential candidate for something we want to use. Developing Angular 2 with TypeScript does not feel like old web development but like writing actual good code, plus the community is huge.

And, if you want to create a mobile app and website chances are very high you can share code between your NativeScript and web app! This is something that will become more and more important. And as NativeScript does not force you to have some special Angular stuff, you could really share that pieces sometimes 1:1 which is currently not possible with Ionic 2.

The next big plus is native performance coming from the native compiled UI components. Of course this makes NativeScript attractive to people who rely on good performance and fear the almighty Webview in hybrid apps.

One thing we haven’t really touched before is the use of native APIs, which comes pretty easy with NativeScript. This means, you can actually call the let’s say iOS UITableViewController directly from code!

Of course this means you need to have some native knowledge, but if you do have it this can sometimes offer you great possibilities as you don’t have to wait for some company to write a wrapper but just directly use it by yourself. For a better explanation, you can watch the NativeScript explanation video here.

Finally I would recommend to try NativeScript to everyone, but especially to those who:

  • like Angular 2 and TypeScript
  • want better performance for Cross Platform apps
  • already have some native experience

These people might benefit the most from it, and that’s again the reason why I said there is space for many frameworks. What these people might like about NativeScript is not helpful at all for others, who are then suited better with a different framework.

Conclusion

My first adventure with NativeScript was interesting, I learned a lot about how things work and I can see the potential benefits for developing cross-platform apps with it. I will give it some more time and maybe more tutorials in the near future to see if it’s something I want to work with more often.

What are your first experiences with NativeScript? Would love to hear them!

A big thank you goes out to Sebastian Witalec again for porting my code from NativeScript 2.1 to 2.2. You can definitely count on the NativeScript team if you encounter any problems!

Happy Coding,
Simon

The post NativeScript Angular 2 Introduction: Why NativeScript Matters appeared first on Devdactic.

5 Simple Hacks to Find App Ideas Absolutely Easy

$
0
0

It’s tricky to get started with your next app. You know you want to create something, either just for learning a language or because you want to build some side income (or for thousand other reasons). But what to do if you just can’t find any good idea to get started, how to find app ideas if you need them?

In this article I will show you my 5 simple hacks to find app ideas absolutely easy. They won’t always be the next big thing – but sometimes you just want ANY idea to get started and feel the flow and energy of working on a side project again.

1. Look through App Store Ratings

This is one of my favorite tactics to find good, sometimes even awesome app ideas. And you can do it simply everyday on your couch while watching TV.

Let’s say you have some broad area you would like to create an app for. Don’t worry if you don’t have it right now, just give yourself a few minutes to think about a broad field you would create something for.

So for example some weeks ago I wanted to create an app in the productivity field, just because I love everything in that field from ToDo apps to time planners and tracking tools. I also recently came across the Eisenhower Method, which seemed kinda interesting to me.

That’s when I started my journey on the App Store. You don’t need to have such a specific idea for now, a bit broader approach at that point is fine as well.

For example on the iOS App Store go to Discover, try to narrow down your topic with the categories they have and start reading. Skip through all the entries, if something looks good check it out, see what the Developer or the company behind the app has also published.

Many of these not so prominent apps are maybe not a success for the company, but they might be something that potentially could be improved.

 appstore-find-app-ideas

Just look for ideas!

Why?

First of all, this gives you all kinds of views on the field you want to create something for. Second, you will see a lot of developers that might have 1 successful app, and a lot of failures before. Which is very typical for just try&error.

You get a sense for what is working, what is interesting and what get’s people engaged. But this is just the first half of the process.

While doing this first part, you might encounter some apps that grab your attention. Maybe they share the same functions, or have the same purpose in that field.

This is now the point where you have a more specific topic (like mine was Eisenhower Method), which you can then again use for searching apps.

At this point you can leave the discover section and actively search for a term or word related to that broad idea or functionality. Now you have a list of quite specific apps to the topic you want to create an app for.

Why should I create an app if there are already 100 apps that look the same?

Hold on my friend, that is not what I want you to do. This wouldn’t be called a hack if there was no trick about that you need to apply!

Now you go through the ratings of those apps and look for 1-3 star ratings. These are the people who are not satisfied with the actual app. Most of the time you might only find a few negative comments, some not really helpful.

But once you get a list of negative points people are mentioning, you know you have found gold!

So when you are that far, you almost know what a better version of an app looks like. This could be “better UI”, “less functionality” or a feature many people wish for. Why don’t you give it to them?

By following this approach you not only get ideas really quick, but you also already know which areas need improvement and special care.

2. Listen to friends, customers, everyone

Listen. Listen. Listen.


Listen. Listen. Listen. That’s where ideas come from.
Click To Tweet


This can often be the key to finding awesome ideas everywhere at every time. You have to develop some kind of passive filter for conversations that get’s triggered once people talk about problems. Sometimes they even talk about the solution!

If you have some kind of business, listening to your customers can be extremely important, because they have real problems that they want to fix. And if you can offer them a solution, they will be more than happy to even pay you for your services. Often, they won’t be the only persons in business that will have that problem!

If you are not in business, maybe you still study, you can apply the same rules to your friends.

Do you remember how they talked about all the problems they have at the last party?

A good hack is to always carry a little notebook (I use this) to make some scribbles in those situations. Because all of those ideas will be lost the next morning after a party for sure. We have gone through this often enough.

So the next time someone talks about their daily problems and says “Why isn’t there an app for this?” I hope you grab a pen or your phone and jot down the next free idea someone just gave to you!

3. Read on Quora

If you are not going to parties, not having any business partners or talking to any other human being (however you manage that), you can still find ideas and inspirations online!

A site I learned to love is Quora. People simply ask questions and other people answer them.

quora-find-app-ideas

The classic game of mankind.

But it’s actually not that boring as it might sound. Those questions are not dumb useless questions, but most of the time really interesting or even quite technical questions!

If you already have a specific area in mind, you could filter the questions for that category and look what people are asking.

Is there a pattern or type of question that get’s asked over and over again?

Make sure to stay up tp date there and check for new questions every now and then if you currently can’t find anything that brings you forward (you could definitely waste hours of your time there, just because it’s interesting.) So in case nothing here for you yet, go to the next point.

4. Scan Online App Wishlists

There are pages online where people simply wish for apps.

Have you heard of them before?

In places like ideaswatch, Reddit or even on a special Github project people can add their ideas for new apps.

reddit find app ideas
Also, if you want direct feedback for an idea you have you can submit it to PreApps and see what others think. Plus you can scan their archive for interesting topics.

Most of the time we just need some inspiration if we are completely out of good ideas for a realistic and profitable next app.

Although all of these places might contain a lot of ideas that are either impossible to create as an app or just a dumb idea at all, these “unrealistic” approaches might be exactly what get’s us out of our old thought patterns.


Unrealistic ideas can help us to leave old thought patterns.
Click To Tweet


Most of the time if we think to hard about a problem or just “I can’t find any good idea” we get into a zone from where we only see a limited horizon. And the first step to be productive and creative again is to leave that point and come back to a more open, dreaming mind.

5. Think about yourself

If nothing of the before has worked for you, we are back at ground zero.

We are on our own to find the next killer app idea.

How can we find app ideas alone?

Well, everyday you live and encounter problems (I hope not to many, but there will be some anyway). And always when you hit a problem in your life you should ask yourself:

Why is there no solution to this problem yet?

Many times the problem is just too small or a good solution is unrealistic. But whenever that’s not the case, you have to think if you could somehow solve this problem.

“We can not solve our problems with the same level of thinking that created them” ― Albert Einstein

You might not know how to create the solution for a problem yet, but maybe just because you have thought about the problem with the same patterns that created it in the first place. As Einstein said, we need to think different to fix those problems.

Find app ideas everywhere

These are just 5 simple Hacks to find app ideas, and there are many more great ways to come up with ideas out there.

So what’s the baseline?

Leaving old thought patterns!

If you are desperately hoping and searching for the holy grail idea for your next app, you are in a zone that does not really support creativity and an open mind. Look around you for inspiration and ideas, combine different thoughts and within no time you will find something that works for you.

Are you currently working on a cool app? Share your thoughts and how you came up with it below, I would love to hear your stories!

Happy Coding,
Simon

The post 5 Simple Hacks to Find App Ideas Absolutely Easy appeared first on Devdactic.

How to Build Ionic 2 Drag and Drop using Dragula

$
0
0

Having drag and drop functionality in your mobile app is very common, but it’s not really inlcuded in the standard Ionic stuff. I looked around and found a great library called Dragula which gives AngularJS apps great features.

Therefore today I will show you how to easily add drag and drop to your Ionic 2 app by including and using ngDragula.

Setting up a blank app

As always we start with a blank Ionic 2 app using TypeScript. We also already install the ng2-dragula library wich is the version of Dragula for Angular 2. So go ahead and run:

ionic start devdactic-drag blank --v2 --ts
cd devdactic-drag
npm install ng2-dragula dragula --save

There are many great examples in the Dragula Demo, basically you can drag an item from one list/div to another defined area. You can also specify all kinds of attributes how the drag or drop feature should behave in special cases.

For us, we simply want to have 2 Ionic lists side by side and drag and drop items between those 2 lists.

Importing and using ngDragula

To use the library we need to import it inside our class and add the directive and provider of ngDragula to our component.

Inside our class we have 2 arrays for our 2 lists. The lists will be filled with *ngFor, but the library will actually take care of moving the dragged item to the new array of our class, so all the data is updated.

Pretty awesome, right?

For an example we also subscribe to the drop event of the DragulaService and create a little alert. This means, whenever we drop something it should appear in the new place and also a popup should come up.

Now go ahead and insert in your app/pages/home/home.ts:

import {Component} from '@angular/core';
import {NavController, Alert} from 'ionic-angular';
import {Dragula, DragulaService} from "../../../node_modules/ng2-dragula/ng2-dragula"

@Component({
  templateUrl: 'build/pages/home/home.html',
  directives: [Dragula],
  providers: [DragulaService],
})
export class HomePage {
  q1 = [];
  q2 = [];

  constructor(private navController: NavController, private dragulaService: DragulaService) {
    for (var i = 0; i < 20; i++) {
      this.q1.push("1. <" + i + ">");
      this.q2.push("2. <" + i + ">");
    }

    dragulaService.drop.subscribe((value) => {
      let alert = Alert.create({
        title: 'Item moved',
        subTitle: 'So much fun!',
        buttons: ['OK']
      });
      this.navController.present(alert);
    });
  }
}

That’s actually everything we need for our little demo to work with. Let’s craft the view around it.

Setting up our view for Drag and drop

As said before, we want to have 2 lists to drop from one to the other. This is no limitation, I actually used 4 different lists inside my recently created app Priortrix.

We give both our lists 50% width using the Ionic 2 grid system.

For Dragula we actually need to define only 2 things:

  • [dragula]: The name of a general bag, should be the same for sources where you want to have drag and drop
  • [dragulaModel]: The actual array inside our class

Open the app/pages/home/home.html and insert:

<ion-header>
  <ion-navbar>
    <ion-title>
      Devdactic Drag & Drop
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <ion-row>
    <ion-col width-50 class="left">
      <div class="header">First Bucket</div>
      <ion-list [dragula]='"my-bag"' [dragulaModel]="q1">
        <button ion-item *ngFor="let item of q1">
          {{item}}
      </button>
      </ion-list>
    </ion-col>

    <ion-col width-50 class="right">
      <div class="header">Second Bucket</div>
      <ion-list [dragula]='"my-bag"' [dragulaModel]="q2">
        <button ion-item *ngFor="let item of q2">
          {{item}}
        </button>
      </ion-list>
    </ion-col>
  </ion-row>
</ion-content>

As you can see, we specify the name "my-bag" to let Dragula know those 2 lists have a connection, and for each list we specify either q1 or q2, the arrays from our previously created class.

Now this should already work, but to get the cool effects you might have seen on the Demo page we need to add some styling (which I found somewhere but I can’t remember where) which uses the CSS names of Dragula.

Adding cool animations

These animations and stylings will add the effect of items floating above the rest while dragging and getting smooth into their new position. Obviously you can change this stuff to whatever you want the animation to look like!

So go ahead and insert in your app/pages/home/home.css:

.header {
  height: 30px;
  padding-left: 5px;
  padding-top: 2px;
  text-align: center;
}

.left {
  border-right: 1px solid #000000;
  padding: 0px;
  overflow: scroll;
}

.right {
  padding: 0px;
  overflow: scroll;
}

// Dragula stuff

.gu-mirror {
  position: fixed !important;
  margin: 0 !important;
  z-index: 9999 !important;
  opacity: 0.8;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
  filter: alpha(opacity=80);
}

.gu-hide {
  display: none !important;
}

.gu-unselectable {
  -webkit-user-select: none !important;
  -moz-user-select: none !important;
  -ms-user-select: none !important;
  user-select: none !important;
}

.gu-transit {
  opacity: 0.2;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
  filter: alpha(opacity=20);
}

Now go ahead and drag and drop all the items of your list!

Conclusion

It’s pretty easy to include a mighty feature like drag and drop with Ionic 2 and Angular 2. If you found libraries like these that are already available with Angular 2, you won’t have any problems most of the time.

What are your experiences with other frameworks for animation or cool features? Let me know your experiences!

Happy Coding,
Simon

Click below for a video version of this tutorial!

The post How to Build Ionic 2 Drag and Drop using Dragula appeared first on Devdactic.

Building Ionic Image Upload With PHP Server

$
0
0

Capturing, storing and uploading images with Ionic is one of the most used functions. Everyone wants to take photos and work with them inside their app, but in my previous guide about using images with Ionic many people encountered problems on Android. Others needed a backend to upload images. And the code is a bit outdated as well.

So in this tutorial we will see how to take a photo or load one from the library, copy that image inside our app folder and finally upload it to a very simple PHP server. In this tutorial we will use Ionic 1 due to the high demand, but if you want an Ionic 2 app for this case as well please leave a comment below!

Let’s get the fun started, this is a real hands-on project and you could take the code as a starter for many other projects.

Setup the Ionic Image Upload Project

WE start with a blank Ionic 1 app and install a handful of Cordova plugins we need to access the camera, the filesystem and so on. Additional we install ngCordova, the Angular 1 wrapper for Cordova plugins.

ionic start devdactic-image-upload blank
cd devdactic-image-upload

# Add Cordova Plugins
ionic plugin add cordova-plugin-file
ionic plugin add cordova-plugin-file-transfer
ionic plugin add cordova-plugin-filepath
ionic plugin add cordova-plugin-camera
ionic plugin add cordova-plugin-actionsheet

# Install ngCordova
bower install ngCordova --save

After setting up our project we need to load the ngCordova lib inside the head section of our index.html before the cordova.js file:

<script src="lib/ngCordova/dist/ng-cordova.js"></script>

Finally make sure to add the ngCordova dependency to the array of dependencies of our app inside the www/app.js:

angular.module('starter', ['ionic', 'ngCordova'])

Now we got a solid amount of plugins and stuff for our app. Note that we need to test this app inside the simulator or a device as we need native functionality, so make sure to add the platform (iOS/ Android) you need to your project.

Creating a simple view

The view of our Ionic image upload app will be very simple. We just need 2 buttons for loading an image and uploading it later. We also want to display the file we took inside the app just to make sure we have the correct one. Go ahead and open the index.html and replace the current body with this:

<body ng-app="starter" ng-controller="ImageCtrl">
  <ion-pane>
    <ion-header-bar class="bar-positive">
      <h1 class="title">Devdactic Image Upload</h1>
    </ion-header-bar>
    <ion-content>
      <img ng-src="{{pathForImage(image)}}" style="width: 100%; height: 100%;">
    </ion-content>
    <ion-footer-bar class="bar bar-positive">
      <div class="button-bar">
        <button class="button icon-left ion-camera" ng-click="loadImage()">Take Photo</button>
        <button class="button icon-left ion-upload" ng-click="uploadImage()" ng-disabled="image === null">Upload</button>
      </div>
    </ion-footer-bar>
  </ion-pane>
</body>

Nothing really special, but note that we will resolve the actual path to the image using a function. By doing this we could always get the path right even after appstart. In this example we are not storing the image, but if you plan to you would only have to store the name of the image and the path to the app folder will always be added.

We will see how this works later, for now e only need a little implementation of our ImageCtrl so open the www/app.js and add:

.controller('ImageCtrl', function ($scope, $cordovaCamera, $cordovaFile, $cordovaFileTransfer, $cordovaDevice, $ionicPopup, $cordovaActionSheet) {
  $scope.image = null;

  $scope.showAlert = function(title, msg) {
    var alertPopup = $ionicPopup.alert({
      title: title,
      template: msg
    });
  };

 // The rest of the app comes in here
});

As you can see, we load quite a bunch of dependencies here. We will see them in action later, for now we only have our empty scope image and a function to display an alert. Let’s continue with the funny part!

Loading camera or library images into our Ionic app

Before we actually capture the image, we want to present the user a simple actionsheet to select between using the camera and loading an image from the photo library. We already installed the needed cordova plugin, so now we simply implement our function to show the actionsheet:

// Present Actionsheet for switch beteen Camera / Library
$scope.loadImage = function() {
  var options = {
    title: 'Select Image Source',
    buttonLabels: ['Load from Library', 'Use Camera'],
    addCancelButtonWithLabel: 'Cancel',
    androidEnableCancelButton : true,
  };
  $cordovaActionSheet.show(options).then(function(btnIndex) {
    var type = null;
    if (btnIndex === 1) {
      type = Camera.PictureSourceType.PHOTOLIBRARY;
    } else if (btnIndex === 2) {
      type = Camera.PictureSourceType.CAMERA;
    }
    if (type !== null) {
      $scope.selectPicture(type);
    }
  });
};

We need to specify some options which we then can pass to the $cordovaActionSheet. When the user selects one of those 2 options, we call our actual image taking function with the specified source type.

The actionsheet will look like this on iOS.
ionic-image-upload-actionsheet
This is our next function, and the biggest one of this tutorial as well. Actually the code is only that long because we have special treatment for Android with photo library, all other cases already work with one part of the function.

I am not completely sure why we need this, but after long testing I found this solution to be working on iOS and Android with Camera and library as well, so if you had problems before, this code might fix it.

So first of all add the code, and we will see how it works below the snippet:

// Take image with the camera or from library and store it inside the app folder
// Image will not be saved to users Library.
$scope.selectPicture = function(sourceType) {
  var options = {
    quality: 100,
    destinationType: Camera.DestinationType.FILE_URI,
    sourceType: sourceType,
    saveToPhotoAlbum: false
  };

  $cordovaCamera.getPicture(options).then(function(imagePath) {
    // Grab the file name of the photo in the temporary directory
    var currentName = imagePath.replace(/^.*[\\\/]/, '');

    //Create a new name for the photo
    var d = new Date(),
    n = d.getTime(),
    newFileName =  n + ".jpg";

    // If you are trying to load image from the gallery on Android we need special treatment!
    if ($cordovaDevice.getPlatform() == 'Android' && sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
      window.FilePath.resolveNativePath(imagePath, function(entry) {
        window.resolveLocalFileSystemURL(entry, success, fail);
        function fail(e) {
          console.error('Error: ', e);
        }

        function success(fileEntry) {
          var namePath = fileEntry.nativeURL.substr(0, fileEntry.nativeURL.lastIndexOf('/') + 1);
          // Only copy because of access rights
          $cordovaFile.copyFile(namePath, fileEntry.name, cordova.file.dataDirectory, newFileName).then(function(success){
            $scope.image = newFileName;
          }, function(error){
            $scope.showAlert('Error', error.exception);
          });
        };
      }
    );
    } else {
      var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
      // Move the file to permanent storage
      $cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
        $scope.image = newFileName;
      }, function(error){
        $scope.showAlert('Error', error.exception);
      });
    }
  },
  function(err){
    // Not always an error, maybe cancel was pressed...
  })
};

The $cordovaCamera.getPicture call starts the photo selection, either by starting the camera or by opening the photo library. This part works fine, but now we actually want to copy that image from wherever it is currently to our app folder.

If we are now on Android and have selected the library as source type, we call some functions to resolveNativePath of the file, because the URL we get from the picker won’t work out of the box. Now we can resolve the correct path to a local filesystem URL and finally $cordovaFile.copyFile to the directory of our app.

We specify the cordova.file.dataDirectory, you can see where those folders are on the ngCordova documentation for the File plugin.

The else part for all other cases is quite short compared to the special treatment, and we do the same thing as above but now we can also call $cordovaFile.moveFile as we are allowed to move the file. In the previous section we could only copy the file to our directory.

Finally, in both cases we apply only the filename to our $scope.image variable, as we will resolve the rest of the URL with a function. You can add this function now:

// Returns the local path inside the app for an image
$scope.pathForImage = function(image) {
  if (image === null) {
    return '';
  } else {
    return cordova.file.dataDirectory + image;
  }
};

We simply return the directory of our app plus the image name. If you plan to store the image names, you can do this and create the correct path after startup again. If you would store the whole path you might get into problems as the path to your app folder could change over time!

So now we are already able to load an image into our app. The next part handles the upload to a simple PHP server.

If you want to learn Ionic 1 in detail, make sure to join my step-by-step course Ionic by Doing!

The image you choose should be visible inside your app view like in the image below.

ionic-image-upload-captured

Uploading our images from the App

The Ionic part for file upload is kinda easy. We need the URL to the server, the file and some parameters and then we can call $cordovaFileTransfer.upload to upload our file.

Sounds easy?

It is indeed, so go ahead and add the image upload function:

$scope.uploadImage = function() {
  // Destination URL
  var url = "http://localhost:8888/upload.php";

  // File for Upload
  var targetPath = $scope.pathForImage($scope.image);

  // File name only
  var filename = $scope.image;;

  var options = {
    fileKey: "file",
    fileName: filename,
    chunkedMode: false,
    mimeType: "multipart/form-data",
    params : {'fileName': filename}
  };

  $cordovaFileTransfer.upload(url, targetPath, options).then(function(result) {
    $scope.showAlert('Success', 'Image upload finished.');
  });
}

Obviously you might have to change the destination URL wherever your PHP server is. This tutorial won’t be complete with a solution for that accepting part, so go ahead to create your little PHP backend!

Creating our simple image upload PHP server

I am not using PHP frequently, but many of you asked for a PHP solution and I found it quite easy to setup this littler server to accept files. I am mostly more a fan of Firebase solutions as a Backend, but for this example PHP works perfectly.

If you have a server you can use that one, otherwise I simply recommend to download XAMPP and install it local.

I’m not going to cover that process since this is about Ionic image upload and not how to configure PHP. If you have set it up, you can first of all create a upload.php to accept uploads:

<?php
header('Access-Control-Allow-Origin: *');
$target_path = "uploads/";

$target_path = $target_path . basename( $_FILES['file']['name']);

if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
    echo "Upload and move success";
} else{
echo $target_path;
    echo "There was an error uploading the file, please try again!";
}
?>

Also, make sure to create a uploads folder next to this file, as it will copy the images into that folder.

Additionally, to see the results of our hard work, I created a little HTML file that will scan the uploads folder and show them so we can directly see if our upload worked, Create this as index.html next to the previous file and insert:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
  <title>Devdactic Image Upload</title>
</head>
<body>
<h1>Ionic Image Upload</h1>
  <?php
  $scan = scandir('uploads');
  foreach($scan as $file)
  {
    if (!is_dir($file))
    {
        echo '<h3>'.$file.'</h3>';
      echo '<img src="uploads/'.$file.'" style="width: 400px;"/><br />';
    }
  }
  ?>
</body>
</html>

Now you got everything in place and can start your Ionic image upload adventures!

If you now pick an image and upload it, you should see this dialog as a result (after finished upload).

 ionic-image-upload-success

Conclusion

There are many problems related to ionic image capturing, loading them to the app and using them later. This tutorials shows a way to bypass those problems on iOS and Android plus how to use the local files inside your app to send them to a PHP server.

If you encounter problems or simply like the tutorial, leave a comment below and share it with your fellow developers!

Happy Coding,
Simon

The post Building Ionic Image Upload With PHP Server appeared first on Devdactic.

How To Build Ionic 2 Tinder Cards Using Angular 2 Swing

$
0
0

The Ionic 2 tinder card swipe feature is a highly request UI behaviour and my previous post about the use of it with Ionic 1 was very popular. For Ionic 2 there is not yet an official component from the Ionic team, but with some help from a different library we can achieve almost the same results.

Follow along this post to get your own Ionic 2 tinder cards or swipeable cards for your next app using the Angular 2 swing package from Kapil Sachdeva. This package is based on the Swing library, a swiepable cards interface.

Starting our app

We begin, as always, with a blank new Ionic 2 project. Currently this post uses the beta 12 of Ionic 2. We additionally use TypeScript and install the before mentioned Angular 2 Swing library with npm. So go ahead and run:

ionic start devdactic-swipe blank --v2 --ts
cd devdactic-swipe
npm install angular2-swing@^0.7.1 --save

For now this is everything we need, so let’s continue with the swipe feature! By the way, our result will look like in this gif:

ionic-2-tinder-behaviour
If you want everything ready to your inbox, just insert your email below.

Building the controller for Tinder Card style swipe

Inside the app/pages/home/home.ts we need to import some components from the angular2-swing library. Additional we need to query some element from our HTML that’s why we import stuff like ViewChild.

In general the interface consists of a stack and an array of cards. You can configure the stack using different parameters like the distance of the thrown out cards, or when a card should be finally thrown out. You can find all of the configuration options here.

We also specify our own function for transform because we want to apply a little red/green background whenever we drag the swipeable card to a side. You could obviously do whatever you want, like fading in a “like” label or something that works for your cards.

After the view is initialized we also subscribe to the throwin event which is called whenever the card is thrown back onto the stack. In that case we go back to our previous white background. We could subscribe to this event either here from the code or directly on the HTML object, it’s up to you

The current code for our page looks like this:

import {Component, ViewChild, ViewChildren, QueryList} from '@angular/core';
import {NavController} from 'ionic-angular';
import {Http} from '@angular/http';
import 'rxjs/Rx';

import {
  StackConfig,
  Stack,
  Card,
  ThrowEvent,
  DragEvent,
  SwingStackComponent,
  SwingCardComponent} from 'angular2-swing';

  @Component({
    templateUrl: 'build/pages/home/home.html',
    directives: [SwingStackComponent, SwingCardComponent]
  })

export class HomePage {
  @ViewChild('myswing1') swingStack: SwingStackComponent;
  @ViewChildren('mycards1') swingCards: QueryList<SwingCardComponent>;
  
  cards: Array<any>;
  stackConfig: StackConfig;
  recentCard: string = '';
  
  constructor(private http: Http) {
    this.stackConfig = {
      throwOutConfidence: (offset, element) => {
        return Math.min(Math.abs(offset) / (element.offsetWidth/2), 1);
      },
      transform: (element, x, y, r) => {
        this.onItemMove(element, x, y, r);
      },
      throwOutDistance: (d) => {
        return 800;
      }
    };
  }
  
  ngAfterViewInit() {
    // Either subscribe in controller or set in HTML
    this.swingStack.throwin.subscribe((event: DragEvent) => {
      event.target.style.background = '#ffffff';
    });
    
    this.cards = [{email: ''}];
    this.addNewCards(1);
  }
}

Our stack also currently has one dummy card. On top of that dummy cards we put our real cards, using data from the Randomuser API.

The first function we add is the one that is called after every move. Here we calculate whether the item is moved to the left or right and based on that decision add a slight green or red background. We also rotate the item a bit to improve the swipe effect of the card.

The next function voteUp is connected through HTML, you will see the connection later. This is simply called whenever a card was thrown out to a side. Based on the boolean we can define whether it’s a like or dislike and display that information below our card stack. Also we need to pop the card and get a new object from the API.

Apparently whenever we add a card to the stack, the card will be added on top. It’s a problem with the Swing library and already discussed here. Maybe this post inspires someone to come up with a solution for this problem to make the swipe card package even better!

Add these functions to your already existing controller now:

// Called whenever we drag an element
onItemMove(element, x, y, r) {
  var color = '';
  var abs = Math.abs(x);
  let min = Math.trunc(Math.min(16*16 - abs, 16*16));
  let hexCode = this.decimalToHex(min, 2);
  
  if (x < 0) {
    color = '#FF' + hexCode + hexCode;
  } else {
    color = '#' + hexCode + 'FF' + hexCode;
  }
  
  element.style.background = color;
  element.style['transform'] = `translate3d(0, 0, 0) translate(${x}px, ${y}px) rotate(${r}deg)`;
}

// Connected through HTML
voteUp(like: boolean) {
  let removedCard = this.cards.pop();
  this.addNewCards(1);
  if (like) {
    this.recentCard = 'You liked: ' + removedCard.email;
  } else {
    this.recentCard = 'You disliked: ' + removedCard.email;
  }
}

// Add new cards to our array
addNewCards(count: number) {
  this.http.get('https://randomuser.me/api/?results=' + count)
  .map(data => data.json().results)
  .subscribe(result => {
    for (let val of result) {
      this.cards.push(val);
    }
  })
}

// http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript
decimalToHex(d, padding) {
  var hex = Number(d).toString(16);
  padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
  
  while (hex.length < padding) {
    hex = "0" + hex;
  }
  
  return hex;
}

I skipped the last two functions because the one is a simple HTTP request and the other transforms a decimal to a hex to achieve the color effect, nothing special. What’s still missing is the HTML view, so let’s continue with that.

The UI for our Tinder Card Style

Our view consists of the 2 elements stack and cards for the Swing component. Our stack will be a surrounding div, which also has the stackConfig assigned and connects the throwout methods with our class.

The card is a simple iteration of Ionic cards over our array, displaying a bit of information from the userobject.

Additional we have a button for like or dislike in case people don’t want to swipe, or just to show that you could call those vents manually if you like to. Now go ahead an open your app/pages/home/home.html and insert:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content class="home" padding>
  <div swing-stack #myswing1 [stackConfig]="stackConfig" (throwoutleft)="voteUp(true)" (throwoutright)="voteUp(false)" id="card-stack">
    <ion-card #mycards1 swing-card *ngFor="let c of cards">
      <ion-item *ngIf="c.picture">
        <ion-avatar item-left>
          <img *ngIf="c.picture"[src]="c.picture.medium">
        </ion-avatar>
        <h2>{{ c.name.first }} {{ c.name.last}}</h2>
        <p>{{ c.email }}</p>
      </ion-item>

      <ion-card-content *ngIf="c.location">
        From: {{ c.location.city }}, {{ c.location.postcode }}<br>
        Phone: {{ c.phone }}
      </ion-card-content>

      <ion-row  *ngIf="c.name">
        <ion-col>
          <button primary clear small (click)="voteUp(true)">
            <ion-icon name="thumbs-up"></ion-icon>
            <div>Yes</div>
          </button>
        </ion-col>
        <ion-col>
          <button primary clear small (click)="voteUp(false)">
            <ion-icon name="thumbs-down"></ion-icon>
            <div>No</div>
          </button>
        </ion-col>
      </ion-row>
    </ion-card>
  </div>
  <p style="text-align: center; width: 100%;">{{ recentCard }}</p>
</ion-content>

The last missing part is a cool UI, because currently the view is not really stacked but more like a list. Therefore, go to your app/pages/home/home.css and insert:

.home {

  #card-stack {
    width: 90%;
    height: 200px;
    background: #047915;
    border: 10px solid #4cb338;
    margin: 100px auto 0;
    position: relative;
  }

  #card-stack ion-card {
    border-radius: 5px;
    position: absolute;
    text-align: center;
    top: 3%;
    height: 90%;
  }

}

This is the final piece, your result should now look somewhat like this:

ionic-2-tinder-card

If you run this tutorial on iOS, make sure to add the NSAppTransportSecurity to the plist of your project like described on Stack overflow.

Conclusion

Using the Angular 2 Swing library with Ionic 2 to achieve Tinder cards is quite easy, thanks again to Kapil who reacted very fast to a request from my side and added more features to the library!

Maybe this post inspires the Ionic team to revive their old Tinder cards component, which good a lot of positive feedback from people back than. Until we got an official Ionic 2 tinder card component, this approach is a good alternative and quite easy to customise for your needs!

Happy Coding,
Simon

The post How To Build Ionic 2 Tinder Cards Using Angular 2 Swing appeared first on Devdactic.

The Ultimate Ionic 2 Cheatsheet

$
0
0

The Ionic CLI was and still is awesome. With Ionic 2 coming, it time to update my previous very popular Ionic Framework 1 cheatsheet to include all the great options you currently have to build hybrid apps!

While most of these commands already existed before, we now have a complete image with all the commands. Some do even have more options than I specified on the cheatsheet, you can find all the options (and maybe missing commands) on the official Github repository for the Ionic CLI.

To use the new features of Ionic 2 (which is now at RC 0) make sure to install it via npm:

npm install -g ionic

To make this graphic less distracting and more helpful I reduced it to what’s important so you can use it as a reference while you develop your next great Ionic app!

Enjoy and share the Ionic 2 Cheatsheet,
Simon
ionic-2-cheatshet

The post The Ultimate Ionic 2 Cheatsheet appeared first on Devdactic.

Building Your Own Simple RSS Reader with Ionic 2

$
0
0

Parsing RSS data is not a simple task given that most feeds are based on XML. Within this post we will build a simple RSS reader with Ionic 2 using the Yahoo API to transform our feeds into more readable JSON.

The Ionic 2 RC0 is out so we can work on a pretty solid foundation and API by now. Changes might still occur, but they hopefully won’t break the code. I give credits to Raymond Camden where I first saw the Yahoo API in action, so follow him, he’s an awesome guy who likes Star Wars and cats.

Let’s dig into the fun and start a blank new app!

Starting a new Ionic 2 App

As always, we use the Ionic CLI to start a blank new Ionic 2 app by passing the –v2 flag. Additional we generate a page and a provider for our app which we can easily use later for our reader. We also install the Ionic storage package using NPM which allows us to store key/value pairs, and finally a cordova plugin to open a browser inside the app. Now go ahead and run from your command line:

ionic start devdactic-rss blank --v2
ionic g page feedList
ionic g provider feedService
npm install @ionic/storage --save --save-exact
ionic plugin add cordova-plugin-inappbrowser

To use our Pages and providers we must properly inject them inside the src/app/app.module.ts so replace everything with:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { FeedListPage } from '../pages/feed-list/feed-list';
import { FeedService } from '../providers/feed-service';
import { Storage } from '@ionic/storage';

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    FeedListPage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    FeedListPage
  ],
  providers: [FeedService, Storage]
})
export class AppModule {}

These are all the resources we need for now, let’s start with the heart of our app first.

If you want the complete template for download, make sure to get it below!

Get the Ionic 2 RSS Template

Enter your Email below to receive the template directly to your inbox!

Powered by ConvertKit

Crafting the RSS Service

The RSS service will take care of delivering all the information our app needs. All the logic for storing and loading feeds plus actually grabbing feed data takes place in this class.

We define 2 classes, FeedItem to hold one article of a feed and Feed to represent an RSS feed from a website. Using TypeScript it’s really a good approach to wrap your information in objects like these!

Open the previously generated provider at src/providers/feed-service.ts and replace everything with:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '@ionic/storage';
import { Observable } from 'rxjs/Observable';

export class FeedItem {
  description: string;
  link: string;
  title: string;

  constructor(description: string, link: string, title: string) {
    this.description = description;
    this.link = link;
    this.title = title;
  }
}

export class Feed {
  title: string;
  url: string;

  constructor(title: string, url: string) {
    this.title = title;
    this.url = url;
  }
}

@Injectable()
export class FeedService {

  constructor(private http: Http, public storage: Storage) {}

  public getSavedFeeds() {
    return this.storage.get('savedFeeds').then(data => {
      let objFromString = JSON.parse(data);
      if (data !== null && data !== undefined) {
        return JSON.parse(data);
      } else {
        return [];
      }
    });
  }

  public addFeed(newFeed: Feed) {
    return this.getSavedFeeds().then(arrayOfFeeds => {
      arrayOfFeeds.push(newFeed)
      let jsonString = JSON.stringify(arrayOfFeeds);
      return this.storage.set('savedFeeds', jsonString);
    });
  }

  public getArticlesForUrl(feedUrl: string) {
    var url = 'https://query.yahooapis.com/v1/public/yql?q=select%20title%2Clink%2Cdescription%20from%20rss%20where%20url%3D%22'+encodeURIComponent(feedUrl)+'%22&format=json';
    let articles = [];
    return this.http.get(url)
    .map(data => data.json()['query']['results'])
    .map((res) => {
      if (res == null) {
        return articles;
      }
      let objects = res['item'];
      var length = 20;

      for (let i = 0; i < objects.length; i++) {
        let item = objects[i];
        var trimmedDescription = item.description.length > length ?
        item.description.substring(0, 80) + "..." :
        item.description;
        let newFeedItem = new FeedItem(trimmedDescription, item.link, item.title);
        articles.push(newFeedItem);
      }
      return articles
    })
  }
}

The getSavedFeeds and addFeed work on our storage object and gather or save a new added Feed. By doing this we can keep the once added Feeds inside our list like in every good Feed reader app!

The getArticlesForUrl is the function doing the work of extracting all the Feed data from one feed using the Yahoo API. It looks a bit weird and I never thought this would work, but it actually fetches the data quite well. The only thing missing here is an image, apparently I found no solution to retrieve that information as well.

Let me know if you can find a solution for this, that would really add a few extra stars to that API.

Once we have the data we apply some transformation to convert the JSON response into FeedItems which we can then return to our view.

We got the heart of the app, the rest now will be easy simply using our service!

Showing and Adding new Feeds inside a Side Menu

As seen before we have the functions to store and retrieve stored Feeds from the storage. We want to have a simple side menu view where we have the different feeds inside the menu while displaying the actual articles from one feed inside the main view.

We start with the class for the side menu so go ahead and insert everything below into the src/pages/home/home.ts:

import {Component, ViewChild} from '@angular/core';
import {NavController, AlertController, Nav} from 'ionic-angular';
import {FeedListPage} from '../feed-list/feed-list';
import {FeedService, Feed} from '../../providers/feed-service';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChild(Nav) nav: Nav;

    rootPage = FeedListPage;
    feeds: Feed[];

    constructor(private navController: NavController, private feedService: FeedService, public alertCtrl: AlertController) {}

    public addFeed() {
      let prompt = this.alertCtrl.create({
        title: 'Add Feed URL',
        inputs: [
          {
            name: 'name',
            placeholder: 'The best Feed ever'
          },
          {
            name: 'url',
            placeholder: 'http://www.myfeedurl.com/feed'
          },
        ],
        buttons: [
          {
            text: 'Cancel',
            role: 'cancel'
          },
          {
            text: 'Save',
            handler: data => {
              let newFeed = new Feed(data.name, data.url);
                this.feedService.addFeed(newFeed).then(
                  res => {
                    this.loadFeeds();
                  }
                );
              }
          }
        ]
      });
      prompt.present();
    }

    private loadFeeds() {
      this.feedService.getSavedFeeds().then(
        allFeeds => {
          this.feeds = allFeeds;
        });
    }

    public openFeed(feed: Feed) {
      this.nav.setRoot(FeedListPage, {'selectedFeed': feed});
    }

    public ionViewWillEnter() {
      this.loadFeeds();
    }
}

We use the ionViewWillEnter to load the feeds from our service, and if we have the data we simply assign it to the this.feeds variable which will be used in our view in the next step.

The actual longer part is to add a feed, which is simply displaying an Alert with 2 inout fields for the URL and a clear name for the Feed. Inside the handler for the result of this alert we can catch the user input and create (add) a new feed again just by using our service and calling a reload on the view to update the list.

If the user selects a feed we set the root of our navigation to the FeedListPage and pass the selected feed object as a parameter. We will see how to handle these params in the next section.

Before we come to that we need to show the list of feeds inside our side menu view, so go ahead and open the src/pages/home/home.html:

<ion-menu [content]="content">
  <ion-toolbar secondary>
    <ion-title>Recent articles</ion-title>
  </ion-toolbar>

  <ion-content>
    <ion-list>
      <button menuClose ion-item *ngFor="let feed of feeds" (click)="openFeed(feed)">
        {{feed.title}}
      </button>
    </ion-list>
    <button ion-button full (click)="addFeed()" action secondary>
      <ion-icon name="add"></ion-icon> Add Feed
    </button>
  </ion-content>

</ion-menu>

<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>

At the bottom we define our navigation where the root is set to the variable rootPage. The rest of the view defines the actual content of the side menu, where we display a list of our feeds and assign click events to each of them. Below the list is a button to add new feeds, which will then bring up the alert view.

So far we are almost done, let’s finish it up with the view for our articles!

Loading Feed Data and Showing Articles

Once the user selects a feed from the side menu we need to update the main view. We already saw how to pass params using the setRoot function, now we need to extract these values inside the constructor of our FeedListPage.

We use again the ionViewWillEnter but add a check if we actually have a selected feed. We also add a little fallback to start loading the first Feed of our array if no feed is selected (at startup).

Our loadArticles is now taking care of loading all the articles for a specific feed, and once we got the value we can set our array of articles and also set a variable to indicate loading progress to false.

Now go ahead and insert in your src/pages/feed-list/feed-list.ts:

import { Component } from '@angular/core';
import { NavController, NavParams} from 'ionic-angular';
import { InAppBrowser } from 'ionic-native';
import { Http } from '@angular/http';
import {FeedService, FeedItem, Feed} from '../../providers/feed-service';

@Component({
  selector: 'page-feed-list',
  templateUrl: 'feed-list.html'
})
export class FeedListPage {
  articles: FeedItem[];
  selectedFeed: Feed;
  loading: Boolean;

  constructor(private nav: NavController, private feedService: FeedService, private navParams: NavParams) {
    this.selectedFeed = navParams.get('selectedFeed');
  }

  public openArticle(url: string) {
    InAppBrowser.open(url, '_blank');
    // window.open(url, '_blank');
  }

  loadArticles() {
    this.loading = true;
    this.feedService.getArticlesForUrl(this.selectedFeed.url).subscribe(res => {
      this.articles = res;
      this.loading = false;
    });
  }

  public ionViewWillEnter() {
    if (this.selectedFeed !== undefined && this.selectedFeed !== null ) {
      this.loadArticles()
    } else {
      this.feedService.getSavedFeeds().then(
        feeds => {
          if (feeds.length > 0) {
            let item = feeds[0];
            this.selectedFeed = new Feed(item.title, item.url);
            this.loadArticles();
          }
        }
      );
    }
  }
}

To finally open an article we can use the Cordova InAppBrowser and simply pass the URL of the feed and also say we want to open it in a blank view.

The view of the articles is again a simple list iterating over our array of articles. We also add the spinner which will depend on the loading variable. Open your src/pages/feed-list/feed-list.ts and insert:

<ion-header>
  <ion-navbar secondary>
    <button ion-button menuToggle>
      <ion-icon name="menu"></ion-icon>
    </button>
    <ion-title *ngIf="!selectedFeed">Newest Articles</ion-title>
    <ion-title>{{selectedFeed?.title}}</ion-title>
  </ion-navbar>
</ion-header>

<ion-content class="feed-list" padding>
  <ion-spinner *ngIf="loading" id="feed-spinner"></ion-spinner>
  <ion-list *ngIf="selectedFeed" class="spinner">
    <ion-item  *ngFor="let item of articles" (click)="openArticle(item.link)" class="feed-article">
      <div class="article-title">{{item.title}}</div><br>
      <p [innerHtml]="item.description"></p>
    </ion-item>
  </ion-list>
  <div *ngIf="!selectedFeed" class="center-placeholder">Please select a feed!</div>
</ion-content>

The description is not simply printed but added as innerHtml as this seemed to work best for whatever comes from the service.

The view looks ok, but it’s never a bad idea to add some styling so we can tweak the appearance with some easy styles inside the src/pages/feed-list/feed-list.scss:

page-feed-list {
  .feed-list {
    background: #d1ffdc;
    .feed-article {
      height: 80px;
      background: #ffffff;
      border-radius: 10px;
      margin-bottom: 10px;
      border-top: 0px;
      color: #000000;
    }
    ion-list > .item:first-child, ion-list > .item-wrapper:first-child .item {
      border-top: 0px;
    }
    ion-list .item .item-inner {
      border-bottom: 0px;
    }
    .article-title {
      font-weight: bold;
    }
  }

  #feed-spinner {
    margin: auto;
    position: absolute;
    top: 0; left: 0; bottom: 0; right: 0;
    height: 100px;
  }

  .center-placeholder {
    margin: auto;
    position: absolute;
    top: 0; left: 0; bottom: 0; right: 0;
    width: 200px;
    height: 100px;
  }
}

Now our own little RSS Reader with Ionic 2 is ready to be used and should look somehow like this:

ionic-2-rss-reader

I added the Devdactic feed for testing, but you can obviously pick any Feed you like (and subscribe to mine in your favorite RSS reader!).

Conclusion

The simple RSS reader using Ionic 2 has it’s limitations as the Yahoo API is not the best API in the world to convert our data from XML to JSON. If you have a good approach please share your thoughts below, also I hope you subscribe to my blog to get future updates and more awesome tutorials!

You can find a video version of this article below!

Happy Coding,
Simon

The post Building Your Own Simple RSS Reader with Ionic 2 appeared first on Devdactic.


Simple Ionic 2 Login with Angular 2

$
0
0

Almost every mobile app nowadays has a login, and using Ionic 2 and Angular it’s pretty easy to craft the UI and logic for a simple Login. My post on simple login with Ionic 1 is one of the most viewed articles, so with the stable release of Ionic 2 in the next time it’s time for an updated (and more stylish) version of that!

In this tutorial we will craft a simple login without a real backend, but with a login screen, register page and a potential logged in screen plus the logic to get to the right screens and perform the right actions.

Setting up a new Ionic 2 app

As always we start with a blank new app and use the Ionic generator command to add 2 pages and a service. Otherwise we don’t need any additional stuff, so go ahead an run:

ionic start devdactic-simpleLogin blank --v2
cd devdactic-simpleLogin
ionic g provider authService
ionic g page register
ionic g page login

This will setup all the needed files in the right places. Currently (version RC1) we have to hook up everything inside the src/app/app.module.ts so open the file and replace everything with:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { LoginPage } from '../pages/login/login';
import { AuthService } from '../providers/auth-service';
import { RegisterPage } from '../pages/register/register';

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    LoginPage,
    RegisterPage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    LoginPage,
    RegisterPage
  ],
  providers: [AuthService]
})
export class AppModule {}

We need to add our pages to the declarations and entryComponents and the service we created to the array of providers.

Finally we need to tell our app to start with our generated LoginPage instead of the default home me page, so open the src/app/app.component.ts and change it to:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from 'ionic-native';
import { LoginPage } from '../pages/login/login';

@Component({
  template: `<ion-nav [root]="rootPage"></ion-nav>`
})
export class MyApp {
  rootPage = LoginPage;

  constructor(platform: Platform) {
    platform.ready().then(() => {
      StatusBar.styleDefault();
    });
  }
}

That’s everything for the basic stuff we need to handle, let’s get to the code for our Ionic Login.

Creating the Authentication service

We use a service to handle the login, register and handling the current user. This service will use hard coded values so you would have to fit in your backend calls at the correct positions. I already choose to return promises because in a real scenario you would have asynchronous calls at these points. If you plan to use this template in your app, it’s easier to integrate those calls later!

We also define a very simple User object which consists of a name and email. It’s easier to work with these classes than always using some object with undefined values, so embrace TypeScript and use classes.

Open the src/providers/auth-service.ts and insert:

import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

export class User {
  name: string;
  email: string;

  constructor(name: string, email: string) {
    this.name = name;
    this.email = email;
  }
}

@Injectable()
export class AuthService {
  currentUser: User;

  public login(credentials) {
    if (credentials.email === null || credentials.password === null) {
      return Observable.throw("Please insert credentials");
    } else {
      return Observable.create(observer => {
        // At this point make a request to your backend to make a real check!
        let access = (credentials.password === "pass" && credentials.email === "email");
        this.currentUser = new User('Simon', 'saimon@devdactic.com');
        observer.next(access);
        observer.complete();
      });
    }
  }

  public register(credentials) {
    if (credentials.email === null || credentials.password === null) {
      return Observable.throw("Please insert credentials");
    } else {
      // At this point store the credentials to your backend!
      return Observable.create(observer => {
        observer.next(true);
        observer.complete();
      });
    }
  }

  public getUserInfo() : User {
    return this.currentUser;
  }

  public logout() {
    return Observable.create(observer => {
      this.currentUser = null;
      observer.next(true);
      observer.complete();
    });
  }
}

As you can see we are working with Observables all the time which would in a real case simply be http calls. But working manually with Observables is also sometimes required so this is a good practice to understand the syntax as well.

At the login we just check if the login is granted (for email “email” and password “pass”) and set the current user. Here you would normally perform your backend request and maybe store a token if you get one. We simply set our current user information and finish the observable.

Inside the register function we can’t do anything as we have no backend, so we only check if we got any values and then return success. This is the place to make a POST request to your server and create the new user!

Let’s see how to use our service in action!

Building the Login

Our login view will consists of 2 inout fields and 2 buttons to either login or create a new account. The input fields are connected to the object registerCredentials inside our class and will be passed to the authService once we hit login.

On register we take the user to another screen. In our example this screen is almost the same as login, but most of the time you want to have some additional input fields for user registration so like the rest of the tutorial this is geared towards a future use case.

Besides these functions the Login has functions to display errors that might arise from the auth service, if the auth service returns that the user is allowed to login we set our root navigation to the HomePage which stands for the logged in area of our app.

Go ahead and open the src/pages/login/login.ts and replace it with:

import { Component } from '@angular/core';
import { NavController, AlertController, LoadingController, Loading } from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';
import { RegisterPage } from '../register/register';
import { HomePage } from '../home/home';

@Component({
  selector: 'page-login',
  templateUrl: 'login.html'
})
export class LoginPage {
  loading: Loading;
  registerCredentials = {email: '', password: ''};

  constructor(private nav: NavController, private auth: AuthService, private alertCtrl: AlertController, private loadingCtrl: LoadingController) {}

  public createAccount() {
    this.nav.push(RegisterPage);
  }

  public login() {
    this.showLoading()
    this.auth.login(this.registerCredentials).subscribe(allowed => {
      if (allowed) {
        setTimeout(() => {
        this.loading.dismiss();
        this.nav.setRoot(HomePage)
        });
      } else {
        this.showError("Access Denied");
      }
    },
    error => {
      this.showError(error);
    });
  }

  showLoading() {
    this.loading = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    this.loading.present();
  }

  showError(text) {
    setTimeout(() => {
      this.loading.dismiss();
    });

    let alert = this.alertCtrl.create({
      title: 'Fail',
      subTitle: text,
      buttons: ['OK']
    });
    alert.present(prompt);
  }
}

The class is ready, now the view. As said before, we need 2 input fields connected to our registerCredentials and 2 buttons. All of that will be wrapped inside a little box so we can apply some cool styling in the next step! Open the src/pages/login/login.html and insert:

<ion-content class="login-content" padding>
  <ion-row class="logo-row">
    <ion-col></ion-col>
    <ion-col width-67>
      <img src="http://placehold.it/300x200"/>
    </ion-col>
    <ion-col></ion-col>
  </ion-row>
  <div class="login-box">
    <form (ngSubmit)="login()" #registerForm="ngForm">
      <ion-row>
        <ion-col>
          <ion-list inset>
            
            <ion-item>
              <ion-input type="text" placeholder="Email" name="email" [(ngModel)]="registerCredentials.email" required></ion-input>
            </ion-item>
            
            <ion-item>
              <ion-input type="password" placeholder="Password" name="password" [(ngModel)]="registerCredentials.password" required></ion-input>
            </ion-item>
            
          </ion-list>
        </ion-col>
      </ion-row>
      
      <ion-row>
        <ion-col class="signup-col">
          <button ion-button class="submit-btn" full type="submit" [disabled]="!registerForm.form.valid">Login</button>
          <button ion-button class="register-btn" block clear (click)="createAccount()">Create New Account</button>
        </ion-col>
      </ion-row>
      
    </form>
  </div>
</ion-content>

The input fields use the [(ngModel)] syntax almost like in AngularJS 1. Our whole login form is actually wrapped inside the form tag where we can set the action for (ngSubmit) which is login in our case. If we now add a button of type=submit we will trigger this form submit function defined in the beginning.

We also set an id for this form which is #registerForm which helps to use it to disable the buttons until all required input fields are filled out!

Pretty cool and easy to use, huh?

Let’s finish the view with some styling to make it look more like a login, so open the src/pages/login/login.scss and insert:

page-login {

  .login-content {
    background: #56CA96;

    .logo-row {
      padding-top: 50px;
      padding-bottom: 20px;
    }

    .login-box {
      background: #399F8B;
      padding: 20px 20px 0px 20px;
      margin-top: 30px;
    }

    ion-row {
       align-items: center;
       text-align: center;
     }

     ion-item {
         border-radius: 30px !important;
         padding-left: 30px !important;
         font-size: 0.9em;
         margin-bottom: 10px;
         border: 1px solid #ffffff;
         border-bottom: 0px !important;
         box-shadow: none !important;
     }

     .signup-col {
       margin: 0px 16px 0px 16px;
       padding-bottom: 20px;
     }

     .item-inner {
       border-bottom-color: #ffffff !important;
       box-shadow: none !important;
     }

     .submit-btn {
       background: #51CFB1;
       border-radius: 30px !important;
       border: 1px solid #ffffff;
     }

     .register-btn {
       color: #ffffff;
       font-size: 0.8em;
     }
  }

}

You resulting login screen will now look like this:

ionic-2-login-template

Crafting the Register page

As our register page will consist of the same fields, it’s more or less the same structure and stuff we already had on our login page.

Let’s start with the class which only needs the register function. On successful registration (in our case almost always) we guide the user back to the login page by calling popToRoot on our navigation.

Open the src/pages/register/register.ts and replace with:

import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';

@Component({
  selector: 'page-register',
  templateUrl: 'register.html'
})
export class RegisterPage {
  createSuccess = false;
  registerCredentials = {email: '', password: ''};

  constructor(private nav: NavController, private auth: AuthService, private alertCtrl: AlertController) {}

  public register() {
    this.auth.register(this.registerCredentials).subscribe(success => {
      if (success) {
        this.createSuccess = true;
          this.showPopup("Success", "Account created.");
      } else {
        this.showPopup("Error", "Problem creating account.");
      }
    },
    error => {
      this.showPopup("Error", error);
    });
  }

  showPopup(title, text) {
    let alert = this.alertCtrl.create({
      title: title,
      subTitle: text,
      buttons: [
       {
         text: 'OK',
         handler: data => {
           if (this.createSuccess) {
             this.nav.popToRoot();
           }
         }
       }
     ]
    });
    alert.present();
  }
}

The rest of our class is more or less the same and the register flow is quite easy as well. WE can use our authentication service and the observable it returns which is almost like in a real scenario.

We continue with the simple HTML view for the register page, which contains the same fields but now has a header bar. As we have pushed the page onto the navigation stack before, we will get the back arrow for free by simply using the nav bar here!

So go ahead an insert in your src/pages/register/register.html:

<ion-header>
  <ion-navbar color="dark">
    <ion-title>Register</ion-title>
  </ion-navbar>
</ion-header>

<ion-content class="login-content" padding>
  <div class="login-box">
    
    <form (ngSubmit)="register()" #registerForm="ngForm">
      <ion-row>
        <ion-col>
          <ion-list inset>
            
            <ion-item>
              <ion-input type="text" placeholder="Email" name="email" [(ngModel)]="registerCredentials.email" required></ion-input>
            </ion-item>
            
            <ion-item>
              <ion-input type="password" placeholder="Password" name="password" [(ngModel)]="registerCredentials.password" required></ion-input>
            </ion-item>
            
          </ion-list>
        </ion-col>
      </ion-row>
      
      <ion-row>
        <ion-col class="signup-col">
          <button ion-button class="submit-btn" full type="submit" [disabled]="!registerForm.form.valid">Register</button>
        </ion-col>
      </ion-row>
      
    </form>
  </div>
</ion-content>

Like before we finish this we by applying some styling so it matches our general color schema. Open the src/pages/register/register.scss and insert:

page-register {
  .login-content {
    background: #56CA96;

    .login-box {
      background: #509287;
      padding: 20px 20px 0px 20px;
      margin-top: 30px;
    }

    ion-row {
       align-items: center;
       text-align: center;
     }

     ion-item {
         border-radius: 30px !important;
         padding-left: 30px !important;
         font-size: 0.9em;
         margin-bottom: 10px;
         border: 1px solid #ffffff;
         border-bottom: 0px !important;
         box-shadow: none !important;
     }

     .signup-col {
       margin: 0px 16px 0px 16px;
       padding-bottom: 20px;
     }

     .item-inner {
       border-bottom-color: #ffffff !important;
       box-shadow: none !important;
     }

     .submit-btn {
       background: #51CFB1;
       border-radius: 30px !important;
       border: 1px solid #ffffff;
     }
  }
}

Nothing really special here, but without it wouldn’t look like a cool login! The last part missing is the inside area after people have logged in.

The inside Member area

If a login was successful people will be send to the HomePage which represents the starting point of our member area. On that page we we now have the ability to access information of a user through our authenticationService.

If you have a real authentication mechanism you would now have perhaps some of the general parameters of the user in his object so you can easily display stuff like his name or an image.

Besides providing this information for the view the HomePage also has the logout function which will inform our AuthenticationService and finally guide the user back to the Login page.

Go ahead and fill the src/pages/home/home.ts with:

import {Component} from '@angular/core';
import {NavController} from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';
import { LoginPage } from '../login/login';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  username = '';
  email = '';
  constructor(private nav: NavController, private auth: AuthService) {
    let info = this.auth.getUserInfo();
    this.username = info.name;
    this.email = info.email;
  }

  public logout() {
    this.auth.logout().subscribe(succ => {
        this.nav.setRoot(LoginPage)
    });
  }
}

The view is again nothing fancy, but we display the information of our logged in user and show the logout button inside the top bar. Create the view inside the src/pages/home/home.html like this:

<ion-header>
  <ion-navbar color="dark">
    <ion-title>
      Member Area
    </ion-title>
    <ion-buttons end>
      <button ion-button (click)="logout()">
        <ion-icon name="log-out"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content class="home" padding>
  <h3>Welcome inside, {{username}}!</h3>
  Your Email is: {{email}}
</ion-content>

Because we want to have a smooth UI that looks the same on all of our pages do me a favour and finish the styling for the template with some color for the home page inside src/pages/home/home.scss:

page-home {
  .home {
    background: #56CA96;
  }
}

That’s it! Now you got your very basic template for navigating from outside to inside plus a register form.

Conclusion

In this tutorial we have created a very basic Ionic 2 login template which can be the base for your next project. Of course you need to plugin your real backend at the correct spots, so this is only the start of your app.

Let me know if you would like to see an in-depth authentication tutorial covering even more aspects in the next tutorial!

Happy Coding,
Simon

The post Simple Ionic 2 Login with Angular 2 appeared first on Devdactic.

Building a Signature Drawpad using Ionic 2

$
0
0

Some time ago I wrote a tutorial on building a signature pad using Ionic 1, and today we are going to do the same but now it’s time for Ionic 2 and Angular 2!

In this tutorial we will use the external angular2-signaturepad library to build a simple app where users can draw/sign something and save that image as data using the Ionic storage.

Setting up our Signature Pad Ionic 2 App

As usual we start with a blank Ionic 2 app. We install the signaturepad library and also the Ionic storage which is by now a standalone package. If you want to use this storage on a device in a safe way make sure to also install the cordova package for sqlite so the storage can use an underlying sqlite database.

ionic start devdactic-pad --blank --v2
cd devdactic-pad
npm install angular2-signaturepad --save
npm install @ionic/storage --save
# Install the cordova plugin to use storage on the device!
cordova plugin add cordova-sqlite-storage --save

Once we are done it’s time to include all of our needed imports and providers inside the src/app.module.ts, so open it and insert:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { SignaturePadModule } from 'angular2-signaturepad';
import { Storage } from '@ionic/storage';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    SignaturePadModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [Storage]
})
export class AppModule {}

As you can see we import the Signaturepad library and put the Storage to our array of providers for our app. Let’s get into the real code now!

Adding the Signature Pad class

Most of the configuration for our Signaturepad comes from inside our HomePage. Inside the view it will be a simple element with some options, so if you want to configure some parameters do it inside the class.

To get a reference to the signaturePad we use the @ViewChild syntax which will give us the according element of the view. We also define an object with some parameters we would like to set, which will be set as configuration object on the element in the view itself.

Whenever we enter this class, we want to check whether we have some stored data of a previous drawing. In that case we set our signature variable to that value as it will be simply loaded inside an image. To save the data was a previously often asked question, so you can see it’s as simple as storing the data you get from the Signaturepad!

Open your src/pages/home/home.ts and replace everything with:

import { Component, ViewChild } from '@angular/core';
import { NavController } from 'ionic-angular';
import { SignaturePad } from 'angular2-signaturepad/signature-pad';
import { Storage } from '@ionic/storage';
import { ToastController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  signature = '';
  isDrawing = false;

  @ViewChild(SignaturePad) signaturePad: SignaturePad;
  signaturePadOptions: Object = { // Check out https://github.com/szimek/signature_pad
    'minWidth': 2,
    'canvasWidth': 400,
    'canvasHeight': 200,
    'backgroundColor': '#f6fbff',
    'penColor': '#666a73'
  };

  constructor(public navController: NavController, public storage: Storage, public toastCtrl: ToastController) {}

  ionViewDidEnter() {
    this.signaturePad.clear()
    this.storage.get('savedSignature').then((data) => {
      this.signature = data;
    });
  }

  drawComplete() {
    this.isDrawing = false;
  }

  drawStart() {
    this.isDrawing = true;
  }

  savePad() {
    this.signature = this.signaturePad.toDataURL();
    this.storage.set('savedSignature', this.signature);
    this.signaturePad.clear();
    let toast = this.toastCtrl.create({
      message: 'New Signature saved.',
      duration: 3000
    });
    toast.present();
  }

  clearPad() {
    this.signaturePad.clear();
  }
}

We got 2 more functions that are called whenever the drawing starts and is complete. We simply change a boolean, as I wanted to show you how you can apply flexible styling to some components, so more on this very soon inside the view.

The last 2 functions can be called from our view to save the current data and clear the pad. In both cases we can use our reference to the pad object and perform actions on it. If we wan to save it we simply get the data of the current image by calling toDataURL(). Afterwards we show a little toast to confirm that it has been saved to the storage.

Creating the Signaturepad view

The final piece that connects everything is our view. We need one drawing area (the area of the Signaturepad) and one image that displays the last piece of fine drawing. Between those elements we put 2 buttons to call our clear and safe functions of our class, so go ahead and put this into your app/src/home/home.html:

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      Devdactic Signature
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <div class="title">Please draw your Signature</div>
  <ion-row [ngClass]="{'drawing-active': isDrawing}">
    <ion-col></ion-col>
    <ion-col>
      <signature-pad [options]="signaturePadOptions" (onBeginEvent)="drawStart()" (onEndEvent)="drawComplete()"></signature-pad>
    </ion-col>
    <ion-col></ion-col>

  </ion-row>
  <button ion-button full color="danger" (click)="clearPad()">Clear</button>
  <button ion-button full color="secondary" (click)="savePad()">Save</button>

  <ion-row>
    <ion-col></ion-col>
    <ion-col width-80>
      <img [src]="signature"/>
    </ion-col>
    <ion-col></ion-col>
  </ion-row>

</ion-content>

As said before we pass the options and the 2 event functions to the signature-pad element which is enough for it to work. We also apply a class to the surrounding row using ngClass to check if a value is set and then apply a special class.

The class is defined inside the src/home/home.scss and just looks like this:

page-home {
  .drawing-active {
    background: #d6fffc;
  }
  .title {
    text-align: center;
    font-weight: bold;
    padding: 10px;
  }
}

So now we got everything we need ready! If you run your app (even inside the browser works) you should see 2 empty areas on first startup. Try to draw on the top area and it safe, you image will be copied to the area below. The result will look like the image below, depending on your drawing skills (mine are very high as you can see):

ionic2-signaturepad-screenshot

Conclusion

In this article you learned how to create a simple drawing input for your Ionic 2 app using the Signaturepad library. Most of the stuff we did some time ago using AngularJS 1 works already with Ionic 2, and it’s sometimes even easier to use. If you have used the Signaturepad with Ionic let me know below how and where you used it!

Happy Coding,
Simon

The post Building a Signature Drawpad using Ionic 2 appeared first on Devdactic.

The Complete Ionic 2 Images Guide (Capture, Store & Upload)

$
0
0

Just recently we saw how to capture, store and upload images with Ionic. This week we update that code to version to to be sure we can perform every action on Ionic 2 images as well!

In this article we will build a simple app to capture images (camera/ library), store it in our apps folder and finally build a simple PHP server to upload our captured images. You don’t need PHP knowledge, this is just an example for a backend and a very simple one as well.

Starting our Ionic 2 Images App

First of all we create a new blank Ionic 2 app. Additional we install a bunch of Cordova plugins, so go ahead and run:

ionic start devdactic-imageupload-2 blank --v2
cd devdactic-imageupload-2
ionic plugin add cordova-plugin-camera
ionic plugin add cordova-plugin-file
ionic plugin add cordova-plugin-file-transfer
ionic plugin add cordova-plugin-filepath

In detail these plugins are used for:

We don’t need any additional providers for this example so we are already good to go. Let’s jump right into our image class!

Building the Ionic 2 images capturing class

To start the capturing process we need to distinguish between camera and library, therefore we will display the user a simple action sheet with those options. Also, we already import all the stuff we need later so don’t worry if they are marked as unused at this point.

We work with the already generated home page, so open the src/pages/home/home.ts and replace everything inside with:

import { Component } from '@angular/core';
import { NavController, ActionSheetController, ToastController, Platform, LoadingController, Loading } from 'ionic-angular';
import { Camera, File, Transfer, FilePath } from 'ionic-native';

declare var cordova: any;

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  lastImage: string = null;
  loading: Loading;

  constructor(public navCtrl: NavController, public actionSheetCtrl: ActionSheetController, public toastCtrl: ToastController, public platform: Platform, public loadingCtrl: LoadingController) {}

  public presentActionSheet() {
    let actionSheet = this.actionSheetCtrl.create({
      title: 'Select Image Source',
      buttons: [
        {
          text: 'Load from Library',
          handler: () => {
            this.takePicture(Camera.PictureSourceType.PHOTOLIBRARY);
          }
        },
        {
          text: 'Use Camera',
          handler: () => {
            this.takePicture(Camera.PictureSourceType.CAMERA);
          }
        },
        {
          text: 'Cancel',
          role: 'cancel'
        }
      ]
    });
    actionSheet.present();
  }
}

The user can select between these 2 options inside the action sheet, and for each we can pass the specific sourceType to our takePicture function which is not yet implemented. Let’s change that, and prepare yourself as this is going to be a bit tricky.

In general we want to call the native camera dialog with some options, and get a path to the image back inside the then block. Once we got the image path we want to copy that file into our own apps directory, just because we might want to store it and make sure the user won’t delete it.

As this is not really working on the combination Android + library we need an additional function that resolves that special image path. But after we got the image right, we do the same stuff as in the regular block:

  1. currentName: Grab the current name of the image from the path
  2. correctPath: Get only the path to the image without the name
  3. copyFileToLocalDir: Copy from the current path to our app and use new name from createFileName

All of that is inside the function below, so add that to your HomePage now:

public takePicture(sourceType) {
  // Create options for the Camera Dialog
  var options = {
    quality: 100,
    sourceType: sourceType,
    saveToPhotoAlbum: false,
    correctOrientation: true
  };

  // Get the data of an image
  Camera.getPicture(options).then((imagePath) => {
    // Special handling for Android library
    if (this.platform.is('android') && sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
      FilePath.resolveNativePath(imagePath)
      .then(filePath => {
        var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
        var correctPath = filePath.substr(0, imagePath.lastIndexOf('/') + 1);
        this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
      });
    } else {
      var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
      var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
      this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
    }
  }, (err) => {
    this.presentToast('Error while selecting image.');
  });
}

After that hard stuff we need some more helper functions we already used inside our previous functions. The 3 functions below are used to create a new image name simply from the current timestamp, to copy a file from one location to our app, to present a message for errors and success and finaly to resolve the path of an image to our current apps folder.

The path to our app can change, so whenever you plan to store these images somehow make sure to save the name of the image and not the complete path as this can change from time to time!

Anyway, for now just add these functions to our HomePage:

// Create a new name for the image
private createFileName() {
  var d = new Date(),
  n = d.getTime(),
  newFileName =  n + ".jpg";
  return newFileName;
}

// Copy the image to a local folder
private copyFileToLocalDir(namePath, currentName, newFileName) {
  File.copyFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(success => {
    this.lastImage = newFileName;
  }, error => {
    this.presentToast('Error while storing file.');
  });
}

private presentToast(text) {
  let toast = this.toastCtrl.create({
    message: text,
    duration: 3000,
    position: 'top'
  });
  toast.present();
}

// Always get the accurate path to your apps folder
public pathForImage(img) {
  if (img === null) {
    return '';
  } else {
    return cordova.file.dataDirectory + img;
  }
}

We are now done with the process of capturing and storing images. Actually it wasn’t that long and quite easy to achieve using the Ionic 2 native wrapper. Let’s continue with the last missing function for our images app before we hook up everything inside the view.

Building the Ionic 2 image upload function

After we have captured the image and moved it into our apps folder, we want to give the user to upload this image. Upload to a server can look very different depending on the endpoint and architecture.

For this example we will make a simple upload to a PHP backend as this is quite usual and lots of you have requests to see it with PHP. If you want to see something different (like POST to a REST API) please let me know below in the comments!

To upload our file we use the FileTransfer plugin we initially installed. We have to create an object of different options which need to be passed to the transfer, you can experiment with them if you need different values or more information that needs to reach the server.

We are also showing a progress indicator as it can sometimes take a few second and it’s a good idea to inform your user about the stuff going on (unless you want to perform the upload hidden in the background).

Now append our last function to the HomePage:

public uploadImage() {
  // Destination URL
  var url = "http://yoururl/upload.php";

  // File for Upload
  var targetPath = this.pathForImage(this.lastImage);

  // File name only
  var filename = this.lastImage;

  var options = {
    fileKey: "file",
    fileName: filename,
    chunkedMode: false,
    mimeType: "multipart/form-data",
    params : {'fileName': filename}
  };

  const fileTransfer = new Transfer();

  this.loading = this.loadingCtrl.create({
    content: 'Uploading...',
  });
  this.loading.present();

  // Use the FileTransfer to upload the image
  fileTransfer.upload(targetPath, url, options).then(data => {
    this.loading.dismissAll()
    this.presentToast('Image succesful uploaded.');
  }, err => {
    this.loading.dismissAll()
    this.presentToast('Error while uploading file.');
  });
}

Right now we are done with the logic but can’t actually use it because the view is still missing, so let’s craft something really simple.

Building the view for our app

Actually we only need an image where we can display the currently captured image and two buttons for capturing and uploading images. We are not storing all of the images, but you can very easily store the names as you can always simply add the rest of the path. This is even recommend as your apps path might change!

Additional we use the [hidden] or [disabled] attribute on some of our elements to hide/disable those elements if we don’t have an image selected yet. Now go ahead and put everything below into your src/pages/home/home.html:

<ion-header>
  <ion-navbar color="primary">
    <ion-title>
      Devdactic Image Upload
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <img src="{{pathForImage(lastImage)}}" style="width: 100%" [hidden]="lastImage === null">
  <h3 [hidden]="lastImage !== null">Please Select Image!</h3>
</ion-content>

<ion-footer>
  <ion-toolbar color="primary">
    <ion-buttons>
      <button ion-button icon-left (click)="presentActionSheet()">
        <ion-icon name="camera"></ion-icon>Select Image
      </button>
      <button ion-button icon-left (click)="uploadImage()" [disabled]="lastImage === null">
        <ion-icon name="cloud-upload"></ion-icon>Upload
      </button>
    </ion-buttons>
  </ion-toolbar>
</ion-footer>

Your app is now ready to run! But keep in mind: We are using Cordova plugins, so this won’t work inside the browser!

To test the app you need to run it on a device and use those functions (or use the simulator and chose the library for images). Also, our backend is not yet existing so the upload won’t work at this point. Anyway, you app should look like below at this point.

ionic-2-images-app

Creating our simple image upload PHP server

As this is the same as the last tutorial about Ionic images I’m not really making any changes to the code.

I am not using PHP frequently, but many of you asked for a PHP solution and I found it quite easy to setup this littler server to accept files. I am mostly more a fan of Firebase solutions as a Backend, but for this example PHP works perfectly.

If you have a server you can use that one, otherwise I simply recommend to download XAMPP and install it local.

I’m not going to cover that process since this is about Ionic 2 image upload and not how to configure PHP. If you have set it up, you can first of all create a upload.php to accept uploads:

<?php
header('Access-Control-Allow-Origin: *');
$target_path = "uploads/";

$target_path = $target_path . basename( $_FILES['file']['name']);

if (move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
    echo "Upload and move success";
} else {
echo $target_path;
    echo "There was an error uploading the file, please try again!";
}
?>

Also, make sure to create a uploads folder next to this file, as it will copy the images into that folder.

Additionally, to see the results of our hard work, I created a little HTML file that will scan the uploads folder and show them so we can directly see if our upload worked, Create this as index.php next to the previous file and insert:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
  <title>Devdactic Image Upload</title>
</head>
<body>
<h1>Ionic Image Upload</h1>
  <?php
  $scan = scandir('uploads');
  foreach($scan as $file)
  {
    if (!is_dir($file))
    {
        echo '<h3>'.$file.'</h3>';
      echo '<img src="uploads/'.$file.'" style="width: 400px;"/><br />';
    }
  }
  ?>
</body>
</html>

Now you got everything in place and can start your Ionic image upload adventures!

If you now pick an image and upload it, you should see this dialog as a result (after finished upload).

ionic-2-images-upload

Conclusion

Just like Ionic 1 it’s quite easy to work with images in Ionic 2. I hope this article helps you to overcome any issues you had while working with Ionic 2 images and files. If you need more guidance on other areas of images, please leave a comment below!

Happy Coding,
Simon

The post The Complete Ionic 2 Images Guide (Capture, Store & Upload) appeared first on Devdactic.

7 Steps to Start, Build and Launch Ionic 2 Apps

$
0
0

The process of starting your next killer Ionic 2 app to finally having your app inside the app store is not always easy. Though, if you split the process into manageable steps and work one by one off you will easily become an app creation machine, as it’s so much fun to build and publish Ionic 2 apps!

How to get from Zero to App Store?

At the beginning of the year I asked the Devdactic readers about their biggest problems related to developing hybrid apps. A common answer was the lack of clear guidance how to get from zero to app store. Although the process can be tricky at some steps and you can waste many hours on different stages where you shouldn’t, everyone can easily start, build and launch Ionic 2 apps today with just a little guidance.

Today I released my new eBook “Ionic 2 From Zero to App Store” in which I describe in detail how to get started and what to do exactly in each of the 7 stages of a project.

ionic-2-zero-to-appstore
If you want to have clear guidance and something you can simply follow, make sure to check out the book now (or grab the preview chapter for a first glance at the content!). The main steps described inside the book can be summarized to points below.

1. Idea Creation

This is the beginning of everything. Every project starts with an idea or even a vision for something. But what to do if you actually want to develop something but lack the idea?

Not everyone has tons of good ideas at hand, though you might dream of your own successful app. Hope is not a strategy, so simply waiting for the golden idea to hit you won’t work most of the times. Therefore, this chapter will give you a more strategic approach to finding new ideas for your next killer app.

2. Wireframing

After having the idea what you are going build, it’s time to lay out a very, very rough structure for your app. This doesn’t have to be a a complete design for your app, but a vision of the app that can be afterwards easily converted to your code and architecture.

If you know which pages and services you gonna need, it’s a lot easier to directly get everything right inside the code the first time you do it. If you keep changing your mind about the flow of your app while already doing the coding you will run into a lot more work and trouble than if you prepare it well.

After this step you should know how many screens your app will have, what the basic structure looks like and how the user can navigate through it. It can be really helpful to do a mockup like this in a tool like JustInMind.

3. Get your Basics right

This step marks the actual start of the development. It’s now time to setup your version control, development environment and everything else if you haven’t done so before. Yes you heard right, you need version control (if you have never used it before).

Even if you work alone using Git will give you a lot more security and speed. Your code is safe inside a repository and synced to a service like e.g. Bitbucket and you can jump in your history or experiment with new features without having to fear that you gonna break everything and can’t go back to your working version.

At this basics step you also start your app and create all the pages, providers and services you have planned for your app. Lucky us, the Ionic 2 generator makes life really easy and helps to connect everything.

After you got the basics, your mockup idea or vision is translated to a clickdummy inside Ionic 2, so the basic construct for the app is ready.

4. Develop your Features

Now the basic app was all fun and easy, but now the real work begins.
We talk about adding the real features like API integration of different services and using the native device features. The stuff that actually makes your app come alive!

This is the core step for a development project and will take the longest, depending of the size of your project and the features that need to be developed. After this step, everything inside your app should work as intended and your app is more or less ready.

5. Styling

While developing your app you can already try to get close to the design, but there are always slight differences as you first want to get it working and then take the time to make it look good. And sometimes you just jump from feature to feature and put on the makeup later.

So this step is meant for fixing everything that’s not already right. With Ionic 2 theming it’s pretty easy to change the UI of your app in a matter of seconds. If you use the correct classes before or apply them now, you can change the complete color scheme of your app only by replacing a few SASS variables.

6. Preparation for Submission

At this point the development (first iteration) is done and you are ready to submit your app almost ready.

There are many assets and information you need to gather and prepare for both iOS and Android app store which you need to prepare. If you have never submitted apps before, you have quite some todos here because you need to setup your developer accounts for both iOS and Android. Also keep in mind, you can only build & submit iOS Apps using a Mac!

If you have a Mac, you need to setup some certificates and manage everything inside your developer profile, so the submission can be painfully if you don’t know where to go and what to do.

7. Launching your App

We got the app, the assets and it’s time to launch! But maybe you want to do an internal launch first? Like having a real launch but just for you or your team. That’s why you can submit your app and have a beta test phase!

This is possible both for iOS and Android, so you can test your app on all the desired devices and see if everything works as intended. If something is broken, go back to step 4 and fix it!

Otherwise if you are happy with your app, it’s time to release it!

After going through the testing programs of iOS and Android it becomes more easy to release your app as most of the information was already needed before. The only thing left now is to wait for your Ionic 2 app to be available on the iOS and Android App Store!

It can be easy

The process doesn’t have to be painful, and if you want to start your first Ionic 2 app today but feel lost, make sure to check out my complete step-by-step guide to start, build and launch your Ionic 2 apps!

ionic-2-zero-to-appstore
If you have already built something using Ionic 2 that can be found inside the iOS or Android app store, leave a comment below. I love to see apps that were built with Ionic 2!

Happy Coding,
Simon

The post 7 Steps to Start, Build and Launch Ionic 2 Apps appeared first on Devdactic.

My 3 Words for 2017

$
0
0

This post is different than the stuff I usually release. Starting in 2017, there will be some more “behind the scenes” content on Devdactic to not only help you along your coding journey but also to share lessons learned in topics related to entrepreneurship, productivity and more personal topics.

To start the year with some goals, I copied the idea of having 3 guidance words for the year from Mike Vardy of the Productivityist. I’m having some more detailed goals as well, but those 3 words can be so simple yet giving your decisions a clear path along the year (The original idea comes from Chris Brogan, but I learned about it through Mike).

Disclosure: Some of the links below are affiliate links, which means that if you choose to make a purchase, I will earn a commission. This commission comes at no additional cost to you.

3 Words for all areas

Although the last year was pretty successful in many areas, there is a lot to improve. You might be happy about some achievements but sad you did not take action on some parts of your life. The start of the year marks a good point to let go of the old regrets of the previous year and to start into a fresh future.

Like Mike I picked 3 words that all start with the same letter (helps to remember them), and my 3 selected words for 2017 will be:

Connect, Cut, Create

These words are not only meant as specific actions, but also as broader topics and areas to work in. Let’s dive into each of them to show you what’s behind the single word.

Connect

Life get’s better with every connection you have. The people around you, your friends and family, but also all the great people you can meet online through discussions or interactions on social media.

connections-2017

In 2017, my focus is to connect with more people. You, as a reader of Devdactic are so important to me and the growth of this platform. Therefore, I want to have more, deeper interactions with all of you.

Connecting with influencers can help you to become more visible to a broader audience, if you are the creator of a blog, product or any kind of service. Therefore, connections should not only be created between people who are on the same knowledge level like you but also to those who you admire.

Reaching out to others for help or guidance is sometimes not easy, but the long term relations that can derive from these occasional conversations can be unbelievable valuable in your future.

By connecting with more people you can at the same forge new relations and become inspired by the work of others. Everyone of us has a story to tell, everyone has different problems, rituals goals so getting to know them helps you to grow as well.

Finally, one of my favourite quotes from Steve Jobs is about connecting:

You can’t connect the dots looking forward you can only connect them looking backwards. – Steve Jobs

It’s true that you can’t predict the outcome of your actions now. Whatever you do, learn or share now might be one dot on a clear path in retrospective. I believe that connections to others are a huge cornerstone along your own journey.

Of course this won’t be easy sometimes, especially time consuming now and then but connecting with people and helping others is something you can’t invest too much into.

Cut

We all have too much of something. In a Podcast episode of Lewis Howes I first heard about the art of becoming a minimalist, which inspired me for this goal.

cut-2017

Let’s be honest, becoming a real minimalist is hard. But I do like the idea of decluttering your life from all the stuff that doesn’t really bring joy. Clothes, the stuff at the lowest shelf of your cupboard or the things you are hoarding in your storage room or cellar.

We buy things and loose the interest in it within a few days or weeks, but we still keep the stuff near.

Why?

It’s hard to let go. But by having less we can actually enjoy things a lot more and value them higher than before.

But this goal is not only about physical things, it’s also about cutting off bad habits like eating too much (and the wrong things) or sticking to old and sometimes bad behaviours that are actually not good for us.

It’s about finally unsubscribing on the 100. newsfeed or spammy email list that you have actually never read (I hope it’s not mine). Negative relations can suck up your energy, so try to reduce or remove these if you can feel they are not good for you.

We all have something we own or do that we could let go of and therefore in 2017 try to cut down what is not essential to you. A great additional book on this is Essentialism: The Disciplined Pursuit of Less which I can highly recommend to everyone who has too much going on in his life!

If you have something that’s not fuelling your dreams, why you still do it? Try to cut and reduce in your life wherever possible to make more space for the really important tasks.

Create

Creating stuff (especially as a software developer) brings joy while doing it and afterwards if you can help others with the outcome of your work.

create-2017

In 2017 I will create more tutorials, products and videos for Devdactic, even on new ares (like the post you are just reading). Besides I hope to create more presentations for public speaking gigs, freelance work and innovative solutions in my day job.

Using your skills to create whatever it is gets you into the flow and leaves a feeling of deep fulfillment. If you have never shared your work or your skills with someone, now is the best time to create your own footsteps.

Besides creating material in a written form as help for others you can also create apps, websites, services and tools that could perhaps become your new startup project sometime. And don’t forget about the learning aspect of every new project or endeavour!

Finally, create moments in your life, every day. Create adventures and share experiences with your loved ones. These moments are priceless and should be created more often than anything else.

Whatever it is that you can create, start it this year.

There will never be a better moment to begin something new than now!

What are your Words?

Hopefully these 3 words inspire you to find your own guidance words for 2017! Think about the areas of your life you want to improve and come up with 3 words.

I would love to hear yours (as part of my first goal connect)!

You can leave them with a short explanation below in the comments or Tweet @schlimmson using the hashtag #3words2017.


My 3 words for 2017: Connect, Cut, Create! #3words2017
Click To Tweet


Happy New Year,
Simon

The post My 3 Words for 2017 appeared first on Devdactic.

Viewing all 183 articles
Browse latest View live