Πώς να δημιουργήσετε την πρώτη σας εφαρμογή Ionic 4 με κλήσεις API

Μόλις παρατηρήσατε ότι κυκλοφόρησε το Ionic 4 και τελικά θέλετε να ξεκινήσετε με την ανάπτυξη εφαρμογών μεταξύ πλατφορμών; Λοιπόν, σήμερα είναι η μέρα σας! Θα συνεχίσουμε να χτίζουμε την πρώτη σας εφαρμογή Ionic 4 με κλήσεις HTTP στην ανοιχτή βάση δεδομένων ταινιών!

Είτε είστε εντελώς νέοι στο Ionic είτε έχετε χρησιμοποιήσει προηγούμενες εκδόσεις, εξετάζουμε όλα τα βασικά. Θα καλύψουμε τον τρόπο ρύθμισης μιας νέας εφαρμογής , δρομολόγησης και ακόμη και κλήσεων API για την εμφάνιση δεδομένων ασύγχρονου εντός της εφαρμογής μας.

Αν θέλετε να μάθετε το Ionic ακόμα πιο γρήγορα, μπορείτε επίσης να δείτε το Ionic Academy που δημιουργήθηκε για προγραμματιστές όπως εσείς!

Έτοιμος ; Πήγαινε !

Ρύθμιση της εφαρμογής Ionic 4 μας

Εάν είστε νέοι στο Ionic πρέπει να βεβαιωθείτε ότι έχετε εγκαταστήσει το Node Package Manager. Εάν έχετε συνεργαστεί με άλλες τεχνολογίες ιστού πριν οι πιθανότητες είναι αρκετά καλές, έχετε ήδη όλα όσα χρειάζεστε.

Εάν δεν έχετε χρησιμοποιήσει το Ionic στο παρελθόν, πρέπει να το εγκαταστήσετε μέσω npm. Μόλις εγκατασταθεί, είστε τελικά έτοιμοι να δημιουργήσετε το έργο Ionic 4!

Για να δημιουργήσετε ένα κενό έργο, μπορείτε να χρησιμοποιήσετε το Ionic CLI, οπότε καταλήγουμε σε ένα νέο έργο Ionic 4 με γωνιακή υποστήριξη ( θα μπορούσατε επίσης να χρησιμοποιήσετε το React ή το Vue, καλύτερη υποστήριξη θα έρθει αργότερα φέτος ).

Μόλις το έργο έχει δημιουργηθεί θα cd στο φάκελο. Χρησιμοποιούμε το CLI, το οποίο χρησιμοποιεί το Angular CLI κάτω από την κουκούλα, για να δημιουργήσουμε νέες σελίδες για την εφαρμογή μας που θέλουμε να εμφανίσουμε.

# Install Ionic if you haven't before npm install -g ionic # Create a blank new Ionic 4 app with Angular support ionic start movieApp blank --type=angular cd movieApp # Use the CLI to generate some pages and a service ionic g page pages/movies ionic g page pages/movieDetails ionic g service services/movie

Τώρα μπορείτε να εμφανίσετε απευθείας την εφαρμογή σας εκτελώντας την ακόλουθη εντολή στο έργο σας:

ionic serve

Αυτό θα ανοίξει το πρόγραμμα περιήγησης με την προεπισκόπηση της εφαρμογής σας, η οποία θα φορτώσει ξανά αυτόματα όταν αλλάξετε οτιδήποτε μέσα στο έργο σας.

Μιλώντας για το έργο, έχουμε πολλά αρχεία και φακέλους εδώ, ας δούμε τι σημαίνει αυτό. Θα επικεντρωθούμε στον φάκελο src της εφαρμογής μας, καθώς δεν χρειάζεται να ανησυχούμε για τα υπόλοιπα προς το παρόν.

Εφαρμογή

Αυτός είναι ο φάκελος στον οποίο θα κάνουμε όλες τις αλλαγές κώδικα που ακολουθούν αργότερα σε αυτό το σεμινάριο. Περιέχει ήδη έναν αρχικό φάκελο που είναι βασικά μια σελίδα όπως δημιουργήσαμε προηγουμένως. Θέλω να έχω όλες τις σελίδες στο δικό τους φάκελο σελίδων, ώστε να μπορείτε να αφαιρέσετε τον αρχικό φάκελο επίσης προς το παρόν.

Ο φάκελος σελίδων περιέχει τις πραγματικές προβολές / σελίδες της εφαρμογής μας, που σημαίνει το στοιχείο που θα δούμε στην οθόνη. Αυτήν τη στιγμή έχουμε ήδη 2 σελίδες εδώ και κάθε σελίδα που δημιουργείτε με το CLI συνοδεύεται από 4 αρχεία:

  • * .module.ts: Η γωνιακή ενότητα για μια σελίδα. Κάθε σελίδα είναι βασικά η δική τους ενότητα (που σχετίζεται με την γωνιακή αρχιτεκτονική) με εισαγωγές και στυλ
  • * .page.html: Η σήμανση HTML για μια σελίδα
  • * .page.scss: Το στυλ για τη συγκεκριμένη σελίδα (περισσότερα για το καθολικό στυλ αργότερα)
  • * .page.spec.ts: Ένα αρχείο δοκιμής που προστίθεται αυτόματα για τη σελίδα σας. Καλό εάν θέλετε να ρυθμίσετε αυτοματοποιημένες δοκιμές μονάδας
  • * .page.ts: Ο ελεγκτής για μια σελίδα που περιέχει τον κώδικα Javascript που διαχειρίζεται τη λειτουργικότητα

Ο φάκελος υπηρεσιών περιέχει την υπηρεσία που δημιουργήθηκε προηγουμένως - πρόκειται για τη δομή της εφαρμογής σας σύμφωνα με τις βέλτιστες πρακτικές και τον διαχωρισμό των ανησυχιών μεταξύ της προβολής και των πραγματικών δεδομένων της εφαρμογής σας. Η υπηρεσία θα φροντίσει να χειριστεί τις κλήσεις API και απλώς θα επιστρέψει τα δεδομένα στην προβολή μας αργότερα!

Περιουσιακά στοιχεία

Αυτός ο φάκελος περιέχει όλες τις εικόνες, τις γραμματοσειρές ή τα στοιχεία που χρειάζεστε για την εφαρμογή σας αργότερα.

Περιβάλλοντα

Από καιρό σε καιρό το έργο σας μπορεί να έχει ένα περιβάλλον ανάπτυξης, στάσης και παραγωγής με διαφορετικούς διακομιστές που στοχεύει η εφαρμογή σας. Ο φάκελος περιβάλλοντος βοηθά στη ρύθμιση πληροφοριών για διαφορετικά περιβάλλοντα. Μπορούμε αργότερα να δημιουργήσουμε την εφαρμογή Ionic με σημαία γραμμής εντολών και παίρνει αυτόματα τις σωστές τιμές. Πολύ βολικό!

Θέμα

Αυτός ο φάκελος περιέχει μόνο το variables.scss που περιέχει προκαθορισμένες πληροφορίες χρώματος από το Ionic. Μπορούμε πάντα να αλλάξουμε αυτό το αρχείο και ακόμη και να χρησιμοποιήσουμε ένα εργαλείο όπως το Ionic Color Generator για να δημιουργήσουμε τη δική μας αρωματική έκδοση αυτού του αρχείου!

Έξω από το φάκελο έχουμε επίσης το global.scss. Εδώ μπορούμε να γράψουμε κάποιο SCSS που θα εφαρμοστεί παγκοσμίως στην εφαρμογή μας. Μπορούμε επίσης να το ορίσουμε μόνο για μία σελίδα στα δικά τους αρχεία στυλ.

Αλλα αρχεία

Το πιο σχετικό από τα άλλα αρχεία μπορεί να είναι το index.html γιατί όπως και με κάθε άλλο ιστότοπο, αυτό το αρχείο σηματοδοτεί το σημείο εισόδου στην εφαρμογή μας! Προς το παρόν, αν και δεν χρειάζεται να αλλάξουμε κάτι εδώ, ας αρχίσουμε τώρα να μπαίνουμε στον πραγματικό κώδικα.

Προαπαιτούμενο δρομολόγιο & κλήσεις HTTP

Με το Ionic 4 προχωράμε από ένα ιδιόκτητο δρομολόγιο στον τυπικό Angular Router. Η σήμανση μπορεί να φαίνεται λίγο πιο δύσκολη στην αρχή, αλλά στην πραγματικότητα έχει απολύτως νόημα.

Για όλες τις συνδέσεις εντός της εφαρμογής σας, ρυθμίζετε τις πληροφορίες δρομολόγησης εκ των προτέρων - όπως ακριβώς περιηγείστε σε έναν ιστότοπο!

Στην εφαρμογή μας χρειαζόμαστε 2 διαδρομές:

  • / ταινίες - Μεταβείτε στην πρώτη μας σελίδα στην οποία θα εμφανίζεται μια λίστα ταινιών
  • / movies /: id - Θέλουμε να μπορούμε να προβάλλουμε τις λεπτομέρειες για μία ταινία, ώστε να προσθέσουμε ένα param : id στη διαδρομή που μπορούμε να επιλύσουμε δυναμικά

Πρέπει επίσης να συνδέσουμε την αντίστοιχη σελίδα ( πιο συγκεκριμένη : η ενότητα της σελίδας) με τη διαδρομή, ώστε η Angular να γνωρίζει πώς να επιλύσει μια συγκεκριμένη διαδρομή. Παρέχουμε αυτές τις πληροφορίες χρησιμοποιώντας το loadChildren το οποίο στην πραγματικότητα παίρνει μόνο μια συμβολοσειρά στη διαδρομή της ενότητας .

Αυτό σημαίνει ότι δεν εισάγουμε πραγματικά άλλη ενότητα εδώ, επομένως, οι σελίδες χρησιμοποιούν τεμπέλης φόρτωση. Αυτό σημαίνει ότι θα φορτωθούν μόνο όταν πλοηγηθούμε εκεί!

Για να ρυθμίσετε τις πληροφορίες δρομολόγησης, ανοίξτε το app / app-routing.module.ts και αλλάξτε το σε:

import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'movies', pathMatch: 'full' }, { path: 'movies', loadChildren: './pages/movies/movies.module#MoviesPageModule' }, { path: 'movies/:id', loadChildren: './pages/movie-details/movie-details.module#MovieDetailsPageModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

By making this change we have also disconnected the home page which was initially in the project (and which you might have deleted already at this point).

Now the app will load our movies page as the first page, great! You should also notice this change in your running ionic serve instance already.

Tip: If you want to get a better feeling for how your app will look on a real device you can also run ionic lab instead of serve but you have to install the package upfront:

# Install the Lab Package npm i @ionic/lab # Run your app with device preview and platform styles ionic lab

This package was previously bundled with every new app but needs to be installed for Ionic 4 now.

/Tip End

We also need to apply another change to our app as we want to make HTTP calls. Therefore we need to import another Angular module for making those requests.

The way of doing this is the same as with Ionic 3. We just need to add the HttpClientModule to our main module file and add it to the array of imports like this inside our app/app.module.ts:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {}

Before we dive into more Ionic 4 code we first have to set up the service that powers our app and handles all the HTTP requests that we later want to call.

Making HTTP Requests

A service is the same as in previous versions a provider and can be injected into our controller in order to call its functions.

In order to use the Open Movie Database you need to request an API key and insert it into our service — the process is free so go ahead right now.

With the API we can now search for strings and get results in form of movies, episodes or even games. Also, we can get detailed information for one specific object of those results so a perfect use case for our first Ionic 4 app!

Our service only needs 2 functions:

  • searchData(): This function searches for results to a specific title and search type – an enum we defined upfront to represent the types that we can pass to the API using TypeScript!
  • getDetails(): This function returns the detailed information for one specific element, will be used on our details page

Both functions will return an Observable which is like a Promise on steroids. No serious, it’s like a stream of events that we can subscribe to. Explaining this concept would take another post. For now, let’s use it and keep in mind that both of our functions are async — they will return the API data not immediately.

Now go ahead and change your services/movie.service.ts to:

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; // Typescript custom enum for search types (optional) export enum SearchType { all = '', movie = 'movie', series = 'series', episode = 'episode' } @Injectable({ providedIn: 'root' }) export class MovieService { url = '//www.omdbapi.com/'; apiKey = ''; // <-- Enter your own key here! /** * Constructor of the Service with Dependency Injection * @param http The standard Angular HttpClient to make requests */ constructor(private http: HttpClient) { } /** * Get data from the OmdbApi * map the result to return only the results that we need * * @param {string} title Search Term * @param {SearchType} type movie, series, episode or empty * @returns Observable with the search results */ searchData(title: string, type: SearchType): Observable { return this.http.get(`${this.url}?s=${encodeURI(title)}&type=${type}&apikey=${this.apiKey}`).pipe( map(results => results['Search']) ); } /** * Get the detailed information for an ID using the "i" parameter * * @param {string} id imdbID to retrieve information * @returns Observable with detailed information */ getDetails(id) { return this.http.get(`${this.url}?i=${id}&plot=full&apikey=${this.apiKey}`); } }

I’ve also added some documentation to the functions — with a tool like Compodoc you could now create nice documentation!

Alright, now we are finally ready for some more Ionic 4 code!

Searching for Movies

We start our apps functionality with the things that happen in the background and then build the view on top of it.

So right now we need to implement the logic to submit a search term and type to our service and receive the results. Therefore, we inject the service through our constructor so it’s available to the class.

In another function that we call searchChanged() we will now simply call the according function of our service and set the result to a local variable b>results. Our view will later handle the data that comes from the API and display it using this variable.

We also keep 2 more variables for the searchTerm and type inside our class that we pass to the service. We will connect with them from the view as well so we can change them.

Now go ahead with the code for your controller inside the pages/movies/movies.page.ts:

import { MovieService, SearchType } from './../../services/movie.service'; import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ selector: 'app-movies', templateUrl: './movies.page.html', styleUrls: ['./movies.page.scss'], }) export class MoviesPage implements OnInit { results: Observable; searchTerm: string = ''; type: SearchType = SearchType.all; /** * Constructor of our first page * @param movieService The movie Service to get data */ constructor(private movieService: MovieService) { } ngOnInit() { } searchChanged() { // Call our service function which returns an Observable this.results = this.movieService.searchData(this.searchTerm, this.type); } }

Now the view which looks a lot like Ionic 3 code, just a few of the elements changed their names and properties. For everyone new to Ionic in general: Welcome to your first Ionic components!

A page can be separated into 3 areas: Header, content, footer. In our case, we don’t want a footer so we only define the header area with a title and the content with our actual elements for the search.

The first element that affects the search is the ion-searchbar which is a simple input you have seen in many apps before to search for a term.

We always want to call our search functionality when the type or searchTerm changes. We can do this by catching the (ionChange) event of some of our elements.

Below we got a select drop down with options and the according value for the different types that we could pass back to the API.

You should have also noticed the [(ngModel)] syntax through which both elements are connected to our controller properties. If one side changes, the other will automatically get the new value as well (also known as 2-way data binding).

So we got the search in place and now add another list with elements below our previous components.

For the list, we use an iteration over our results variable. Because this variable is an Observable (remember the implementation in our service) we need to add an Angular Pipe “| async” to it. The view subscribes to the Observable and handles the changes accordingly.

We also add the routing directly to this element by using [routerLink]. We construct the path that we want to open when we click on the element. We use the imdbID property of the item so we can resolve the information on our details page later.

Besides that, we create the markup for one item using the Poster which is an image, the title, year and finally also a cool icon at the and based on the type of the item. Yes, those cool icons are already bundled with your app and are called Ionicons!

With all of that in mind change your pages/movies/movies.page.html to:

  My Movie Search      Select Searchtype  All Movie Series Episode      

{{ item.Title }}

{{ item.Year }}

By now you should be able to search for a specific term inside your app and get a list of results — that’s already a big win!

If you are coming form Ionic 3 you might have also noted another new property called slot so here’s some info on that:

Ionic 4 components are built using Stencil (yeah, they actually created that tool as well!) so they are standard web components — you could import them basically everywhere on the web! These components also use the Shadow DOM API and are basically living outside of the scope of your regular DOM elements.

That means also standard styling will sometimes not affect these components like it was possible in previous versions!

In order to get information into these components, we can inject certain parts of HTML into their slots that are defined on these elements. You can see how their implementation looks like on the example of the ion-item we used here.

Presenting Detailed Information

Ok enough of background information, let’s put some more work into the details page of our app. We have implemented a route and we also created a button that passed an ID with that route so the details page will be open, but we need to get access to the ID!

With previous Ionic versions we could easily pass whole objects to new pages, this is now not a best practice anymore. Instead, we pass only small chunks of information (like an ID) with the URL. Otherwise, you would end up with a huge JSON stringified term inside the URL. This isn’t really something we want to have.

To get access to this ID field (that we already defined inside our routing in the beginning) we can use the ActivatedRoute and its properties.

So after we extract the ID from the params we can make another call to our service (that we injected through the constructor again) and get the detailed information for whatever ID we got.

Nothing really new so let’s add the following code to our pages/movie-details/movie-details.page.ts:

import { MovieService } from './../../services/movie.service'; import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-movie-details', templateUrl: './movie-details.page.html', styleUrls: ['./movie-details.page.scss'], }) export class MovieDetailsPage implements OnInit { information = null; /** * Constructor of our details page * @param activatedRoute Information about the route we are on * @param movieService The movie Service to get data */ constructor(private activatedRoute: ActivatedRoute, private movieService: MovieService) { } ngOnInit() { // Get the ID that was passed with the URL let id = this.activatedRoute.snapshot.paramMap.get('id'); // Get the information from the API this.movieService.getDetails(id).subscribe(result => { this.information = result; }); } openWebsite() { window.open(this.information.Website, '_blank'); } }

We also added another function to open a website using the window object and the information from the data of the API that we stored in the local information variable.

Now we just need to create a view based on the JSON information of the API. It always helps to log() out the info you got so you see keys that you can use to display some values.

In our case, we use the Ionic card component and add the image and some items with information and more icons (did I say I really like the Ionicons?).

We also added a button below that card that will be displayed if the result information contains the website key. We just have to add our function to the (click) event of the button in order to hook everything up!

On another note, we also have to add an ion-back-button to the header of that page in order to get a nice little back arrow to our previous movie list page. This was automatically done in v3 but needs to implemented manually as of v4!

Now finish your details view by changing your pages/movie-details/movie-details.page.html to:

     {{ information?.Genre }}       {{ information.Title }}   {{ information.Year }}     {{ information.Plot }}   {{ information.imdbRating }}    {{ information.Director }}    {{ information.Actors }}    Open Website    

If you now take a look at your browser you might notice that the image looks waaaay to big as its taking all the space available. Let’s change this through some good old CSS so open your pages/movie-details/movie-details.page.scss and insert:

.info-img { max-height: 30vh; object-fit: contain; padding: 10px; }

Now our results look a lot more appealing.

We can search, select a movie type, dive into a search result and have a fully functional Ionic 4 app with HTTP calls finished!

Conclusion

While it was a straight forward experience to build our first Ionic 4 app there are so many things we haven’t talked enough about.

UI patterns like Tabs and side menu, CSS variables, responsive layout and PWA to just name a few on the side of Ionic and Angular.

And we haven’t even touched the Cordova side of things to actually build this app into a real native mobile app!

If you want to learn how to develop Ionic 4 apps as fast as possible and get them to the iOS & Android app stores quickly you can join the Ionic Academy today and enjoy expert screencasts, a library of quick wins and a community to support you on your journey!

And of course, I (Simon) am also present inside to answer all your questions all the time

You can also find a video version of this guide below!

Αρχικά δημοσιεύθηκε στο ionicacademy.com στις 24 Ιανουαρίου 2019.