#alertcontroller
Explore tagged Tumblr posts
Text
Detect Long Press Gesture iOS Tutorial
Long-press gestures are a type of a continuous gesture. UIKit will detect if a press is pushed long instead of a single tap. In this tutorial a long-press gesture is detected, which will display an an alert view. This tutorial is made with Xcode 9 and built for iOS 11.
Open Xcode and create a new Single View App.
For product name, use IOS11LongGestureTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Go to the Storyboard and drag a Button to the main view. Set the title of the button to "Press me". Select the Button and select the Auto Layout align button. Select the "Horizontally in Container" checkbox and click "Add 1 Constraint".
Select the Button and select the Auto Layout pin button. Pin the Button to the top and and click "Add 1 Constraint".
Drag a Long Press Gesture Recognizer from the Object Library on top of the Button. The Storyboard should look like this.The Storyboard should look like this.
Select the Assistant Editor and make sure the ViewController.swift is visible. Ctrl and drag from the Long Press Gesture Recognizer to the ViewController class and create the following Action
Ctrl and drag from the Long Press Gesture Recogniser to the Button and select delegate. The button will now detect the long press gesture.
Go to the ViewController.swift file and implement the handleGesture method
@IBAction func handleGesture(_ sender: UILongPressGestureRecognizer) { if sender.state == UIGestureRecognizerState.began { let alertController = UIAlertController(title: nil, message: "Long-Press Gesture Detected", preferredStyle: UIAlertControllerStyle.alert) alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil)) self.present(alertController, animated: true, completion: nil) } }
The Began UIRecognizerState is a continuous state. If this is recognised an Alert View is Presented. Build and Run the project and press long on the Press me Button.
You can download the source code of the IOS11LongGestureTutorial at the ioscreator repository on Github.
1 note
·
View note
Text
95% off #Full Swift 3 Course. From Dummy to Advance. Build 60+ Apps – $10
The Complete iOS Developer Course. Learn Full Swift Language from Scratch and become iOS Paid Professional from Beginner
Beginner Level, – 44.5 hours, 326 lectures
Average rating 4.4/5 (4.4 (78 ratings) Instead of using a simple lifetime average, Udemy calculates a course’s star rating by considering a number of different factors such as the number of ratings, the age of ratings, and the likelihood of fraudulent ratings.)
Course requirements:
You need only OS X (Mac) No pre knowledge required
Course description:
You’re here to learn every single point of iOS Development? You want to fill gaps in your knowledges? You want to learn Full Complete Swift 3 in one course? Maybe you already know something about Swift and iOS… but you want to write perfect, clear, smooth, BEST CODE.
YOU’RE IN THE RIGHT PLACE: If you start right now – you can create any app you have in your mind of any difficulty type in only 4 weeks.
WHY EXACTLY ME: My name’s Akhmed. I am the creator of most popular coding courses, like:
– Create Full Instagram Clone with Swift & Xcode
– Create Social App on Custom Backend with Swift, PHP, MySQL, HTML
I highly recommend this course. Ahmed Idigov does an absolutely fantastic job with this course. I have completed a few other related courses on Udemy that were good courses but Ahmed’s instruction really sets this course apart from others. In addition, this course is 100% up-to-date. Everything that Ahmed explained throughout the course worked just as he demonstrated. I especially appreciate this because I did not have to spend additional time on Google searching for answers. Great course! – J. Alvardo
Perfect course to get started with building a real apps. Ahmed explained all the features that every app needs. With Ahmed I start to earn money! I like his all courses! – M. Alrashidi
I PROMISE YOU:
I am working to enhance your knowledges and your experience of development. I promise, you will learn all coding aspects that never been shown in other courses or tutorials. I know what needs to be covered. If you don’t like it, I guarantee full money back!
Akhmed’s courses are very Good. It is better than all the other course I have tried! I like he is covering what others do not. Great Job! Thanks for your efforts! – M. Kayne
I though I knew enough about Swift. When I started to watch I realized that I did not know anything! Thank you very much for your great course! – J.J. Abrams!
I am fresh in development, but with Akhmed I already released my first app in App Store. Now it brings me good income! – D. Ather
Sign up today and you’ll get:
+45 hours content Full knowledges about iOS development Full Swift 3 Language Course Build +60 different apps Code and practice every element of iOS HD 1080p 7/24 hours live access to me Know all about development
If you’re ready to become an Advance in development, enroll right now and start to become a Real Professional of iOS Developer!
I was a courier, I did not have any programming knowledges. But now I became iOS Developer! Now I can realize any of my project alone. – P. Batista
I like how simply Akhmed is coding… without complication! I think even kid can understand him. Thanks for a great courses! – S. Spinoza
I suggest his courses to everyone who want learn everything about programming without wasting a time. – K. Sreedhar
From Dummy to Advance in 4 weeks
First Look at Swift Introduction to Xcode Hello World App Label Button TextField ImageView TextView Slider Switch Activity Indicator ProgressView Stepper DatePicker PickerView ScrollView All about Views AlertController ActionSheet All about Navigation ToolBar WebView Auto-Layout Pin Auto-Layout Align Alignment ViewController NavigationController TableViewController TableViewCell XIB & NIB Segues Customized TableView TableView Programmatically SearchBar CollectionViewController Customized CollectionView CollectionView Programmatically TabBar Segmented Control PageViewController PageControl ContainerView SplitViewController PickerController Tap Gesture Pinch Gesture Rotate Gesture Swipe Gesture Pan Gesture Edge Pan Gesture Long Press Gesture UserDefaults Global Variables and Constants Notifications JSON CoreData Working Files Custom Fonts All About Layers 3D Action Peak & Pop Controllers Media Player Maps Animation Custom Animated Segues and many many more
We start from basics to build up your confiden
Reviews:
“This course is a gem. The best iOS course for beginner in my opinion. It is even better than the highest rated iOS courses on udemy. I will surely have solid foundation to move on to the advance topics once i completed this course, definitely taking the other courses from Akhmed. Please add more content like working with camera, microphones, firebase etc.” (Harry Ng)
“pros: 1. very detail and go through almost all things cons: 1. accent is too heavy, sometimes i have to guess what he says 2. recording quality is poor, sometimes the noise make my ear hurt 3. dig deep is good, but some part i think it took too long and too much(like programmatically UI)” (Nplus chang)
“Talented and experienced teacher. Introducing a deeper look into each iOS Swift element, which is great if you want to become an advanced in iOS development.” (Alexey Gofman)
About Instructor:
Akhmed Idigov
Hello! My name is Akhmed! And I would love to teach you to programming. I have many years of development experience. I am watching a lot of tutorials everywhere, so I know what I should cover to bring you something new – more than just average knowledges. With me you will become professional developer. Get ready and go ahead together
Instructor Other Courses:
Create Social App on Custom Backend on Swift PHP MySQL HTML Akhmed Idigov, Head of Development (121) $10 $200 Create FULL INSTAGRAM Clone with Swift and Xcode. Be advance …………………………………………………………… Akhmed Idigov coupons Development course coupon Udemy Development course coupon Mobile Apps course coupon Udemy Mobile Apps course coupon Full Swift 3 Course. From Dummy to Advance. Build 60+ Apps Full Swift 3 Course. From Dummy to Advance. Build 60+ Apps course coupon Full Swift 3 Course. From Dummy to Advance. Build 60+ Apps coupon coupons
The post 95% off #Full Swift 3 Course. From Dummy to Advance. Build 60+ Apps – $10 appeared first on Udemy Cupón/ Udemy Coupon/.
from Udemy Cupón/ Udemy Coupon/ http://coursetag.com/udemy/coupon/95-off-full-swift-3-course-from-dummy-to-advance-build-60-apps-10/ from Course Tag https://coursetagcom.tumblr.com/post/156224673633
0 notes
Text
How to Build an Ionic 5 Calendar with Modal & Customisation
Having a calendar component in your Ionic app could be an essential element for your whole app experience, and while there’s not a standard solution, there are a lot of free components we can use.
In this post we will use one of the best calendar components for Ionic called ionic2-calendar. Don’t worry about the name – it was updated for all versions and works fine with Ionic 5 as well!
We will integrate the component into our app and also create a simple modal so you could use the calendar sort of like a date picker as well!
Getting Started
First of all we need a new Ionic app and install the calendar. We also generate another page that we will later use for our modal:
ionic start ionCalendar blank --type=angular cd ./ionCalendar npm install ionic2-calendar ionic g page pages/calModal
To use the calendar, you need to import it into the according page module. If you also want to localisee it for a specific language, you can use the registerLocaleData from Angular and import the language package you need. In my example I simply used the German language, but there are many more available!
Go ahead and change your home/home-module.ts to this now:
import { NgModule, LOCALE_ID } from '@angular/core'; import { CommonModule } from '@angular/common'; import { IonicModule } from '@ionic/angular'; import { FormsModule } from '@angular/forms'; import { HomePage } from './home.page'; import { HomePageRoutingModule } from './home-routing.module'; import { NgCalendarModule } from 'ionic2-calendar'; import { CalModalPageModule } from '../pages/cal-modal/cal-modal.module'; import { registerLocaleData } from '@angular/common'; import localeDe from '@angular/common/locales/de'; registerLocaleData(localeDe); @NgModule({ imports: [ CommonModule, FormsModule, IonicModule, HomePageRoutingModule, NgCalendarModule, CalModalPageModule ], declarations: [HomePage], providers: [ { provide: LOCALE_ID, useValue: 'de-DE' } ] }) export class HomePageModule {}
That’s the only thing you need to do upfront for your calendar component!
Creating a Basic Calendar
To setup the calendar you need an array of events (which you could e.g. load from your API) and some basic settings for the calendar like the mode and the currentDate, which basically marks today in your calendar.
The mode specifies the view of the calendar, and you can select between month, week and day view.
Let’s go through the basic functions we add to our class:
next/back: Move the calendar view to the next month/week/day based on the current mode using the viewchild we added
onViewTitleChanged: Will be called by the calendar and reflects the current title of your view. This could also be customised with a special formatter as well!
onEventSelected: Called when you click on an entry in the calendar. In our case we simply present an alert with the information of the event.
createRandomEvents: Fill the calendar with some dummy data for testing, copied from the demo code.
removeEvents: Removes all events
You can either completely set the eventSource array to a new value, or otherwise also push single events to the source. We will see how the second part later in combination with our modal.
For now though go ahead and change the home/home.page.ts to:
import { CalendarComponent } from 'ionic2-calendar/calendar'; import { Component, ViewChild, OnInit, Inject, LOCALE_ID } from '@angular/core'; import { AlertController, ModalController } from '@ionic/angular'; import { formatDate } from '@angular/common'; import { CalModalPage } from '../pages/cal-modal/cal-modal.page'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { eventSource = []; viewTitle: string; calendar = { mode: 'month', currentDate: new Date(), }; selectedDate: Date; @ViewChild(CalendarComponent) myCal: CalendarComponent; constructor( private alertCtrl: AlertController, @Inject(LOCALE_ID) private locale: string, private modalCtrl: ModalController ) {} ngOnInit() {} // Change current month/week/day next() { this.myCal.slideNext(); } back() { this.myCal.slidePrev(); } // Selected date reange and hence title changed onViewTitleChanged(title) { this.viewTitle = title; } // Calendar event was clicked async onEventSelected(event) { // Use Angular date pipe for conversion let start = formatDate(event.startTime, 'medium', this.locale); let end = formatDate(event.endTime, 'medium', this.locale); const alert = await this.alertCtrl.create({ header: event.title, subHeader: event.desc, message: 'From: ' + start + '<br><br>To: ' + end, buttons: ['OK'], }); alert.present(); } createRandomEvents() { var events = []; for (var i = 0; i < 50; i += 1) { var date = new Date(); var eventType = Math.floor(Math.random() * 2); var startDay = Math.floor(Math.random() * 90) - 45; var endDay = Math.floor(Math.random() * 2) + startDay; var startTime; var endTime; if (eventType === 0) { startTime = new Date( Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + startDay ) ); if (endDay === startDay) { endDay += 1; } endTime = new Date( Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + endDay ) ); events.push({ title: 'All Day - ' + i, startTime: startTime, endTime: endTime, allDay: true, }); } else { var startMinute = Math.floor(Math.random() * 24 * 60); var endMinute = Math.floor(Math.random() * 180) + startMinute; startTime = new Date( date.getFullYear(), date.getMonth(), date.getDate() + startDay, 0, date.getMinutes() + startMinute ); endTime = new Date( date.getFullYear(), date.getMonth(), date.getDate() + endDay, 0, date.getMinutes() + endMinute ); events.push({ title: 'Event - ' + i, startTime: startTime, endTime: endTime, allDay: false, }); } } this.eventSource = events; } removeEvents() { this.eventSource = []; } }
With that in place we are ready for a basic view of our calendar.
We add some buttons to later trigger our modal and also the dummy functions to fill and clear the array of events.
Besides that we can use a cool segment from Ionic to easily switch between the three different calendar modes, which works by simply changing the mode property!
Additionally we add the helper functions to move left and right in the calendar (which also simply works by sliding the view!) and in the center the title of the current view that we see, which will be updated once we change to another month (or week, or day..).
The calendar itself has a lot of properties that we can or should set. The ones we use are:
eventSource: The array of events which will be displayed
calendarMode: The view mode as described before
currentDate: The today date
onEventSelected: Called when we click on a day with event
onTitleChanged: Triggered when we change the view
start/step: Additional settings for the different views
Now we can go ahead with our home/home.page.html and change it to:
<ion-header> <ion-toolbar color="primary"> <ion-title> Ionic Calendar </ion-title> <ion-buttons slot="end"> <ion-button (click)="openCalModal()"> <ion-icon name="add" slot="icon-only"></ion-icon> </ion-button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> <ion-segment [(ngModel)]="calendar.mode"> <ion-segment-button value="month"> <ion-label>Month</ion-label> </ion-segment-button> <ion-segment-button value="week"> <ion-label>Week</ion-label> </ion-segment-button> <ion-segment-button value="day"> <ion-label>Day</ion-label> </ion-segment-button> </ion-segment> <ion-row> <ion-col size="6"> <ion-button (click)="createRandomEvents()" expand="block" fill="outline"> Add random events </ion-button> </ion-col> <ion-col size="6"> <ion-button (click)="removeEvents()" expand="block" fill="outline"> Remove all events </ion-button> </ion-col> </ion-row> <ion-row> <!-- Move back one screen of the slides --> <ion-col size="2"> <ion-button fill="clear" (click)="back()"> <ion-icon name="arrow-back" slot="icon-only"></ion-icon> </ion-button> </ion-col> <ion-col size="8" class="ion-text-center"> <h2></h2> </ion-col> <!-- Move forward one screen of the slides --> <ion-col size="2"> <ion-button fill="clear" (click)="next()"> <ion-icon name="arrow-forward" slot="icon-only"></ion-icon> </ion-button> </ion-col> </ion-row> <calendar [eventSource]="eventSource" [calendarMode]="calendar.mode" [currentDate]="calendar.currentDate" (onEventSelected)="onEventSelected($event)" (onTitleChanged)="onViewTitleChanged($event)" startHour="6" endHour="20" step="30" startingDayWeek="1" > </calendar> </ion-content>
The standard calendar should work now, and you can also see how it looks per default with some random events!
Adding Events with Calendar Modal
Although the component is meant for something else, I thought it might look cool inside a custom modal as some sort of date picker – and it does!
Therefore we will add a new function to our page that presents our modal and catches the onDidDismiss event, in which we might get back a new event that we then add to our eventSource.
Here we can see the different of pushing an event – we also need to call loadEvents() on the calendar component in order to update the data!
Since we assume that we add an all-day event in our example, I manually set the end time to one day later here. Feel free to use custom times or add another ion-datetime to the modal in your example to pick an exact time!
Now go ahead and change the home/home.page.ts to:
async openCalModal() { const modal = await this.modalCtrl.create({ component: CalModalPage, cssClass: 'cal-modal', backdropDismiss: false }); await modal.present(); modal.onDidDismiss().then((result) => { if (result.data && result.data.event) { let event = result.data.event; if (event.allDay) { let start = event.startTime; event.startTime = new Date( Date.UTC( start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate() ) ); event.endTime = new Date( Date.UTC( start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate() + 1 ) ); } this.eventSource.push(result.data.event); this.myCal.loadEvents(); } }); }
We’ve also added a custom class to the modal to make it stand out more like an overlay. To use the styling, we need to declare it inside the global.scss like this:
.cal-modal { --height: 80%; --border-radius: 10px; padding: 25px; }
Now we got a nice looking modal and only need some more input fields and the calendar component once again.
Like before, we need to add it first of all to the module file, so in our case change the cal-modal/cal-modal.module.ts to:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { IonicModule } from '@ionic/angular'; import { CalModalPageRoutingModule } from './cal-modal-routing.module'; import { CalModalPage } from './cal-modal.page'; import { NgCalendarModule } from 'ionic2-calendar'; @NgModule({ imports: [ CommonModule, FormsModule, IonicModule, CalModalPageRoutingModule, NgCalendarModule ], declarations: [CalModalPage] }) export class CalModalPageModule {}
Since we now don’t want to display any events, we need only a handful of functions.
We need an empty event object that will be passed back to our initial page inside the dismiss() function of the modal, and we need to react to the view title changes and click events on a time slot.
To store it correctly, we also need to transform the data we get inside the onTimeSelected() to a real date object!
Now open the cal-modal/cal-modal-page.ts and change it to:
import { Component, AfterViewInit } from '@angular/core'; import { ModalController } from '@ionic/angular'; @Component({ selector: 'app-cal-modal', templateUrl: './cal-modal.page.html', styleUrls: ['./cal-modal.page.scss'], }) export class CalModalPage implements AfterViewInit { calendar = { mode: 'month', currentDate: new Date() }; viewTitle: string; event = { title: '', desc: '', startTime: null, endTime: '', allDay: true }; modalReady = false; constructor(private modalCtrl: ModalController) { } ngAfterViewInit() { setTimeout(() => { this.modalReady = true; }, 0); } save() { this.modalCtrl.dismiss({event: this.event}) } onViewTitleChanged(title) { this.viewTitle = title; } onTimeSelected(ev) { this.event.startTime = new Date(ev.selectedTime); } close() { this.modalCtrl.dismiss(); } }
The last missing piece is the modal view with some items as input fields and the calendar component just like before, but this time without any events!
You might have noticed the strange modalReady variable already. I couldn’t make the calendar work correctly when deployed to a device, since I assume the view wasn’t rendered correctly and something internally broke.
By hiding it until the view has finished loading we can easily fix this, and in reality you actually won’t even notice it!
Warp up the implementation with the code for the cal-modal/cal-modal.page.html:
<ion-toolbar color="primary"> <ion-buttons slot="start"> <ion-button (click)="close()"> <ion-icon name="close" slot="icon-only"></ion-icon> </ion-button> </ion-buttons> <ion-title></ion-title> <ion-buttons slot="end"> <ion-button (click)="save()"> <ion-icon name="checkmark" slot="icon-only"></ion-icon> </ion-button> </ion-buttons> </ion-toolbar> <ion-content> <ion-item> <ion-label position="stacked">Title</ion-label> <ion-input tpye="text" [(ngModel)]="event.title"></ion-input> </ion-item> <ion-item> <ion-label position="stacked">Description</ion-label> <ion-input tpye="text" [(ngModel)]="event.desc"></ion-input> </ion-item> <calendar *ngIf="modalReady" [calendarMode]="calendar.mode" [currentDate]="calendar.currentDate" (onTitleChanged)="onViewTitleChanged($event)" (onTimeSelected)="onTimeSelected($event)" lockSwipes="true" > </calendar> </ion-content>
Now you are able to open the modal, set a date and some information and our initial page will create the event and add it to the source for the calendar!
Customising the Calendar View
Because the last time we used the component a lot of you asked about customisation, let’s add a few more things today.
First, we might wanna get rid of the list below the month view in our modal, since the calendar has no events in that place anyway.
There’s no setting to hide it (at least I didn’t find it) but we can hide the list by using the correct CSS class and access the encapsulated calendar component like this in our cal-modal/cal-modal.page.scss:
:host ::ng-deep { .monthview-container { height: auto !important; } .event-detail-container { display: none; } }
Using CSS is one way to customise it, and another great way to change the appearance of the calendar is using custom templates for specific parts of the calendar.
Let’s for example change the look and color of a cell inside the calendar so it has a more rounded, different color and also shows the number of events on that specific date.
We could do this by creating a template and passing it to the monthviewDisplayEventTemplate property of the calendar like this inside the home/home.page.html:
<calendar [eventSource]="eventSource" [calendarMode]="calendar.mode" [currentDate]="calendar.currentDate" (onEventSelected)="onEventSelected($event)" (onTitleChanged)="onViewTitleChanged($event)" startHour="6" endHour="20" step="30" startingDayWeek="1" [monthviewDisplayEventTemplate]="template" > </calendar> <ng-template #template let-view="view" let-row="row" let-col="col"> <div [class.with-event]="view.dates[row*7+col].events.length"> <div class="indicator-container"> <div class="event-indicator" *ngFor="let e of view.dates[row*7+col].events"></div> </div> </div> </ng-template>
As you can see we also added our own CSS rules in there, which we could now define either for our own template or additionally some rules for the calendar itself (following the style like we did in the modal) right inside the home/home.page.scss:
.indicator-container { padding-left: 0.5rem; padding-bottom: 0.4rem; } .event-indicator { background: var(--ion-color-success); width: 5px; height: 5px; border-radius: 5px; display: table-cell; } :host ::ng-deep { .monthview-primary-with-event { background-color: white !important; } .monthview-selected { background-color: var(--ion-color-success) !important; } } .with-event { background-color: var(--ion-color-primary); border-radius: 15px; }
Now the view looks a lot different, and this hopefully gives you an idea how you can customise basically every part of this great component!
Conclusion
There are not a lot of components that exist since years and get updates for all major Ionic versions, but this calendar is one of them. Kudos again to the creator!
If you are looking for an alternative, also check out my post on the Angular calendar.
You can also find a video version of this tutorial below.
youtube
The post How to Build an Ionic 5 Calendar with Modal & Customisation appeared first on Devdactic.
via Devdactic https://ift.tt/2VMWq05
0 notes
Text
Error Domain=NEVPNErrorDomain Code=4 “configuration is stale” UserInfo={NSLocalizedDescription=configuration is stale} While connecting to VPN Server
I’m working on a VPN Application, and in my application I’m trying to connect to VPN using IkEv2 protocol. But I’m unable to connect to VPN. Im using UISwitch to connect/disconnect to VPN server. Here is my code:
storing VPN Password in Keychain..
override func viewDidLoad() { super.viewDidLoad() let keychain = KeychainSwift() keychain.set("*****", forKey: "vpnPassword") NotificationCenter.default.addObserver(self, selector: #selector(ViewController.VPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
Switch to connect/disconnect VPN server..
@IBAction func switchButton(_ sender: UISwitch) { switchConntectionStatus.isOn = false if !isConnected { initVPNTunnelProviderManager() } else{ //Removing the current VPN configuration from the caller's VPN preferences.. vpnManager.removeFromPreferences(completionHandler: { (error) in if((error) != nil) { print("VPN Remove Preferences error: 1") } else { self.vpnManager.connection.stopVPNTunnel() self.labelConntectionStatus.text = "Disconnected" self.switchConntectionStatus.isOn = false self.isConnected = false } }) } }
initiating VPN tunnel..
func initVPNTunnelProviderManager(){ //loading the current VPN configuration from the caller's VPN preferences.. self.vpnManager.loadFromPreferences { (error) -> Void in if((error) != nil) { print("VPN Preferences error: 1") } else { let p = NEVPNProtocolIKEv2() p.username = "**" p.remoteIdentifier = "**" p.serverAddress = "**" let keychain = KeychainService() let data = keychain.load(key: "vpnPassword") p.passwordReference = data p.authenticationMethod = NEVPNIKEAuthenticationMethod.none p.useExtendedAuthentication = true p.disconnectOnSleep = false self.vpnManager.protocolConfiguration = p self.vpnManager.isEnabled = true ////saving the current VPN configuration from the caller's VPN preferences.. self.vpnManager.saveToPreferences(completionHandler: { (saveError) -> Void in if((saveError) != nil) { print("VPN Preferences save error: (saveError!)") } else { self.vpnManager.loadFromPreferences(completionHandler: { (loadError) in if((loadError) != nil) { print("VPN Preferences load error: (loadError!)") } else { var startError: NSError? do { try self.vpnManager.connection.startVPNTunnel() } catch let error as NSError { startError = error print("Vpn Manager Connection Error: (startError!)") } catch { print("Fatal Error") fatalError() } if((startError) != nil) { print("VPN Preferences error: 3") let alertController = UIAlertController(title: "Oops..", message: "Something went wrong while connecting to the VPN. Please try again.", preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default,handler: nil)) self.present(alertController, animated: true, completion: nil) print("Alert Controller: (startError!)") } else { self.VPNStatusDidChange(nil) print("Start VPN") } } }) } }) } } }
changing the status accordingly by calling VPNStatusDidChange..
@objc func VPNStatusDidChange(_ notification: Notification?) { print("VPN Status changed:") let status = self.vpnManager.connection.status switch status { case .connecting: print("Connecting...") self.labelConntectionStatus.text = "Connecting..." self.switchConntectionStatus.isOn = false self.isConnected = false break case .connected: print("Connected") self.labelConntectionStatus.text = "Connected" self.switchConntectionStatus.isOn = true self.isConnected = true break case .disconnecting: print("Disconnecting...") self.labelConntectionStatus.text = "Disconnecting..." self.switchConntectionStatus.isOn = false self.isConnected = false break case .disconnected: print("Disconnected") self.labelConntectionStatus.text = "Disconnected..." self.switchConntectionStatus.isOn = false self.isConnected = false break case .invalid: print("Invalid") self.labelConntectionStatus.text = "Invalid Connection" self.switchConntectionStatus.isOn = false self.isConnected = false break case .reasserting: print("Reasserting...") self.labelConntectionStatus.text = "Reasserting Connection" self.switchConntectionStatus.isOn = false self.isConnected = false break } }
Im following this tutorial to save and load password from Keychain. http://blog.moatazthenervous.com/create-a-key-chain-for-apples-vpn/.
This is how my output looks like..
Archive from: https://stackoverflow.com/questions/59029058/error-domain-nevpnerrordomain-code-4-configuration-is-stale-userinfo-nslocali
from https://ift.tt/33xpxoZ
0 notes
Video
youtube
Part 12 how to use alerts in ionic
in this video, i will show you that how you can use alerts in you ionic application.
Alerts are a great way to offer the user the ability to choose a specific action or list of actions. They also can provide the user with important information, or require them to make a decision (or multiple decisions).
From a UI perspective, Alerts can be thought of as a type of “floating” modal that covers only a portion of the screen. This means Alerts should only be used for quick actions like password verification, small app notifications, or quick options. More in-depth user flows should be reserved for full-screen Modals.
step 1 first import this in your page:
import { AlertController } from 'ionic-angular';
step 2 inside class constructor create instance
export class MyPage { constructor(public alertCtrl: AlertController) { }
step 3 create method and call inside button showAlert() { let alert = this.alertCtrl.create({ title: 'dotnetlab!', subTitle: 'notification from dotnetlab', buttons: ['OK'] }); alert.present(); } }
step 4 call inside button
<button ion-button (click)="showAlert()">click me</button>
====================================================
to download full source code and presentation visit our wesite and Blog
website : - http://dotnetlab.in/
source code : - https://github.com/rahuljograna
facebook page :- https://www.facebook.com/DotnetLab-1896440207343189/
visit my blog : - http://aspnetinhindi.blogspot.in
follow me on twitter : https://twitter.com/THEJOGRANA
0 notes
Link
Envato Tuts+ Code http://j.mp/2t0tb9d
One of Ionic's strengths is in the services that it offers on top of the framework. This includes services for authenticating users of your app, push notifications, and analytics. In this series, we're learning about those services by creating apps which make use of them.
In this post, we're going to take a look at Ionic Deploy. This service allows you to publish changes to your Ionic app without the need for recompiling and re-submitting it to the app store. This is very useful for quickly pushing bug fixes, minor updates and other cosmetic changes to the app. With the "Deploy Channels" feature, you can also perform A/B tests by introducing different code changes to different deploy channels.
Not all changes that you want to introduce to your app can be pushed using Ionic Deploy, though. Only changes to your HTML, CSS, JavaScript, and assets under your www directory can be pushed this way. Binary changes such as updates to the Cordova platform version, Cordova plugins (either updating existing ones or adding new ones), and app assets such as the icon and splash screen cannot be pushed using Ionic Deploy.
How It Works
In your Ionic app, you can have code that will check for available deployments (updates). By default, it will check for deployments in the production channel. But you can also specify other channels to receive updates from.
You can then push your changes using the ionic upload command. This will upload your changes to Ionic Cloud. Once they're uploaded, you can choose which channel you wish to deploy to, and whether to deploy now or at a later time.
Deploying to a channel that your app is monitoring will trigger the code in your app to execute. That code is then responsible for downloading the update, extracting it, and reloading the app to apply the changes.
What You'll Be Building
In this post, you'll be using the command line to push the changes and test if the deploy works as expected. To keep things simple, the changes that we're going to introduce will be mainly to the UI. For every deploy, we're going to change the version number displayed for the app. We're also going to change the image displayed on the app to show that assets can be updated as well.
Setting Up
Now that you have an idea of how Ionic Deploy works and what you will be building, it's time to get your hands dirty by actually creating an app which uses Ionic Deploy. Start by bootstrapping a new Ionic app:
ionic start --v2 deployApp tabs
The command above will create a new app using the tabs template. Navigate inside the deployApp directory once it's done installing:
cd deployApp
Next, you need to install the @ionic/cloud-angular package. This is the JavaScript library for the Ionic Cloud service. It allows us to interact with the Ionic Deploy service and other Ionic services via JavaScript code.
npm install @ionic/cloud-angular --save
Once that's done installing, you can now initialize a new Ionic app based on this app. Before you do so, make sure that you already have an Ionic account. The command line tool will prompt you to log in with your Ionic account if you haven't done so already.
ionic io init
This will create a new app named "deployApp" (or whatever you named your app when you bootstrapped a new Ionic app) under your Ionic apps dashboard.
Once you've verified that the app is listed on your Ionic dashboard, go back to the terminal and install the Deploy plugin:
cordova plugin add ionic-plugin-deploy --save
Note that this plugin is the one which actually does the heavy lifting. The @ionic/cloud-angular package simply exposes the APIs required for easily working with the Ionic services inside an Ionic app.
Working With Deploys
Now that you have done all the necessary setup, it's time to add the code for checking and applying updates. But before you do that, first serve the app through your browser:
ionic serve
This allows you to check whether the code that you've added is working or not. This way you can make the necessary corrections as soon as you see an error.
Open the src/app/app.module.ts file. Under the SplashScreen import, import the services needed for working with Ionic Cloud:
import { SplashScreen } from '@ionic-native/splash-screen'; // add the following: import { CloudSettings, CloudModule } from '@ionic/cloud-angular';
Next, add the app_id of your Ionic app. You can find this on your Ionic app dashboard, right below the name of the app.
const cloudSettings: CloudSettings = { 'core': { 'app_id': 'YOUR IONIC APP ID' } };
Once you've added that, you can now include it as one of the modules of the app:
@NgModule({ declarations: [ //... ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), CloudModule.forRoot(cloudSettings) // <-- add this ], });
Next, open the src/app/app.component.ts file. Right below the TabsPage import, include the following:
import { TabsPage } from '../pages/tabs/tabs'; // add these: import { AlertController, LoadingController } from 'ionic-angular'; import { Deploy } from '@ionic/cloud-angular'; // import the Deploy service from @ionic/cloud-angular package
In the constructor(), add the services that we imported earlier:
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, public deploy: Deploy, private alertCtrl: AlertController, private loadingCtrl: LoadingController){ //... }
Setting the Deployment Channel
Since we're still developing the app, set the deployment channel to dev:
this.deploy.channel = 'dev';
Later on, if you want to switch to the production channel, you can simply remove this line as production is the default channel for deployments. If you have created another channel, you can also include its name here.
Working With Snapshots
You can access an array of snapshots that have been previously downloaded by the app. The snapshots variable is an array containing the IDs of each of the snapshots.
this.deploy.getSnapshots().then((snapshots) => { console.log('now getting snapshots...'); console.log(snapshots); });
We won't really be using snapshots for this app, but it's good to know that the app is storing this type of information for later use. In the example below, we'll go through the list of old snapshots and delete each one to free up some space on the device.
snapshots.forEach((snapshot_id) => { this.deploy.getMetadata(snapshot_id).then((metadata) => { // do something with metadata }); // delete snapshot this.deploy.deleteSnapshot(snapshot_id); });
Checking for Updates
To check for updates, use the check() method. This returns a boolean value that tells you whether a new snapshot is available or not. By default, the latest deploy will create a new snapshot. So only the latest deploy will be applied if you pushed two updates consecutively.
this.deploy.check().then((snapshotAvailable: boolean) => { // ... });
If a snapshot is available for download, you can get additional information about it by calling the getMetaData() method. This metadata can be added to a deploy through the Ionic app dashboard. Key-value pairs can be added here, and each of them becomes available as a property for the metadata object. Later on, we will be using metadata to customize the messages shown in the app every time a new update becomes available.
if (snapshotAvailable) { // get metadata this.deploy.getMetadata().then((metadata) => { console.log('now getting metadata..'); console.log(metadata); }); }
Next, show a confirmation alert message to let the user decide whether they want to download the update or not:
let alert = this.alertCtrl.create({ title: 'Version ' + metadata.version + ' is available', message: 'Do you want to download this update?', buttons: [ { text: 'No', role: 'cancel', handler: () => { // do some stuff (e.g. add analytics code for counting how many users didn't apply the update) } }, { text: 'Yes', handler: () => { // proceed with downloading the update } } ] }); alert.present();
You might be concerned that this would annoy the user if they continue to receive the prompt to update their app if they keep responding "No". More often that not, though, this is actually a good thing. There shouldn't be any reason for a user to reject an update if it's going to improve their experience.
Downloading and Applying Updates
When the user agrees, you can go ahead and download the update. This may take a while depending on your internet connection and your device. Once the update is downloaded, show a loader to attract the user's attention while it extracts. Once it's extracted, reload the app and hide the loader.
this.deploy.download().then(() => { // download is done console.log('download completed!'); // show loader let loading = this.loadingCtrl.create({ content: 'Now reloading the app...' }); loading.present(); // extract the update this.deploy.extract().then(() => { console.log('extract completed!'); this.deploy.load(); // reload the app to apply the changes console.log('reload completed!'); loading.dismiss(); }); });
Take a look at what the updated app.components.ts file should look like after all those changes.
Installing the App on the Device
Now that the code for checking deploys is added, we can build the app and install it on a device. The rest of the changes that we're going to introduce will be primarily pushed through the Ionic Deploy service.
Go ahead and add the android platform to your Ionic project and build the .apk file with the following commands:
ionic platform add android ionic build android
This will create an android-debug.apk file inside the platforms/android/build/outputs/apk folder. Copy it to your device and install it.
Pushing Changes
Now it's time for us to push some changes to the app. To try it out, just make some minor changes to the app UI. And now you can upload the changes:
ionic upload
Adding Metadata
Once it's done uploading, a new entry will be listed in your Recent Activity. Click the Edit link of that entry. This will allow you to add a note, versioning information and metadata to that specific release. It's always a good idea to add a note so you know what that specific release is all about. Once you've done so, click on the Metadata tab and add the following:
Then click on the Save button to commit your changes. Finally, click on the Deploy button to deploy the release. Once the app picks up on the change, the metadata that you supplied also becomes available.
You can see that it now shows the version number of the release:
Versioning
Sometimes you will push an update out with Ionic Deploy, but also rebuild and ship those packages to the bundled app in the App Store. Watch out, though, because Ionic doesn't know that your app already contains that update, and your app will prompt the user to download the latest updates the first time your app is run.
The versioning feature can help prevent this. With the versioning feature, you can specify the version of the app which can receive the updates:
Minimum: deploys only if the current app version is higher or equal to this version.
Maximum: deploys only if the current app version is equal or lower than this version.
Equivalent: do no perform a deploy if the current app version is equal to this version.
You can add versioning information by clicking on the EDIT link on a specific release, and then going to the VERSIONING tab. From there, you can specify the versions (either iOS or Android) that you want to target.
What Ionic does is compare this version with the one that you specified in your config.xml file:
If the app version falls between the minimum and maximum specified, the release is picked up. And if the app version is equal to the equivalent version value, the release is ignored. So for the above screenshot, if the version indicated in the config.xml file is 0.0.1, the release will be ignored by the app.
Asset Updates
The next change that we're going to make is to show an image.
The first thing that you need to do is find an image. Put it inside the src/assets/img folder and link it from the src/pages/home/home.html file:
<ion-header> <ion-navbar> <ion-title>Home</ion-title> </ion-navbar> </ion-header> <ion-content padding> <ion-card> <img src="assets/img/lightning.png" /> <ion-card-content> <ion-card-title> Version 4 </ion-card-title> </ion-card-content> </ion-card> </ion-content>
Upload your changes as a new release to Ionic Deploy.
ionic upload
Once uploaded, go to your Ionic app dashboard and update the release with a note and the corresponding version in the metadata. Save the changes and deploy it.
Opening the app should now pick up this new release, and updating it would apply the changes to the UI.
Deploy Channels
By default, Ionic Deploy has three channels which you can deploy to: dev, staging, and production. But you can also create new channels for your app to listen for updates on. You can do that by clicking on the gear icon on the Ionic Deploy tab on your app dashboard:
This is useful for things like A/B testing, so you can push specific changes to specific users only.
Don't forget to update your code to use that specific deploy channel:
this.deploy.channel = 'me';
Rollback
If you've pushed something you shouldn't have, you could use the rollback feature. With this feature, you can push a previous release back to your users.
Note that you can't fix broken code by rolling back! For example, if you have a syntax error in your JavaScript code, it will break the whole app and the code for checking for updates won't ever run. To fix those kinds of errors, the only thing you can do is release a new version on the app store.
You can rollback by clicking on the Roll back to here link on any given deploy.
This will ask you to confirm whether you want to roll back or not. Once confirmed, it will be automatically set as the current release. So the code for picking up new releases will recognize it as the latest release and will prompt users to update. Rolled back releases will have an orange refresh icon.
You can also deploy a specific release by clicking on the Deploy link beside the release that you want to deploy.
Using Git Hooks
You can automate the deployment of app updates on Ionic Deploy with Git hooks. Git hooks allow you to execute scripts before or after specific Git events such as commit, push, and receive. In this case we will be using the pre-push hook to upload our changes to Ionic Cloud right before the git push command does its thing.
Start by renaming the sample pre-push script to the actual name recognized by Git:
mv .git/hooks/pre-push.sample .git/hooks/pre-push
Open the file in your text editor and replace its contents with the following:
#!/bin/sh echo now pushing changes to Ionic deploy ionic upload
Now commit your changes and push them to a remote repo:
git add . git commit -m "make some changes..." git push origin master
Right before the git push command is executed, ionic upload will be executed.
You can also automatically deploy the release if you want:
#!/bin/sh echo now pushing changes to Ionic deploy ionic upload --deploy dev
This won't work for our example, though, because you can't specify metadata!
If you want to take the deployment process further, I recommend you check out the HTTP API for Ionic Deploy. This allows you to programmatically deploy changes to your app from your Continuous Integration server. It allows you to update the version numbers and metadata on your deployments as well. All of this can be done automatically and without ever touching the Ionic app dashboard.
Conclusion
That's it! In this tutorial you've learned about Ionic Deploy and how you can use it to push updates to your Ionic app. This is a powerful feature which allows you to build a robust versioning and update system into your app.
Stay tuned for more content on Ionic and on cloud services like Ionic Deploy! If you want a complete introduction to getting started with Ionic 2 app development, check out our course here on Envato Tuts+.
Ionic
Get Started With Ionic 2
Reginald Dawson
And check out some of our other posts on Ionic and cross-platform mobile app development.
Ionic 2
Code Your First Ionic 2 App: A Photo Sharing App
Wernher-Bel Ancheta
Mobile Development
Introducing Vue and Weex for Native Mobile Apps
Lawrence Turton
App Templates
15 Best Ionic App Templates
Ashraff Hathibelagal
http://j.mp/2s2syP4 via Envato Tuts+ Code URL : http://j.mp/2etecmc
0 notes
Text
Events - iOS Universal Events App Template (Swift)
New item has been added on CodeHolder.net https://codeholder.net/item/mobile/events-ios-universal-events-app-template-swift
Events - iOS Universal Events App Template (Swift) iOS, Android and Web versions can share the same Parse database Apr 28th 2017 • Added an AlertController into the 'submitEventButt()' in SubmitEvent.swift, in order to show up an alert telling you that your
0 notes
Text
How to Build an Ionic 4 Calendar App
Because there is still no calendar component directly shipping with Ionic 4 it’s time to revisit how to build one yourself using a great package we already used in a previous post.
The problem with creating a tutorial like this is that the need for a calendar view varies in almost every app. We’ll dive into building a calendar using the ionic2-calendar package which offers some different views and can be customised to some degree, but if you have very specific requirements you might need to create everything from the ground up yourself.
I’ve also talked about alternatives and using a different package inside Building a Calendar for Ionic With Angular Calendar & Calendar Alternatives.
Starting our Calendar
We start with a blank app and add our calendar package. Don’t be shocked by the name – it still works great with v4 so go ahead and run:
ionic start devdacticCalendar blank --type=angular cd devdacticCalendar npm i ionic2-calendar
Now we don’t need to add it to our main module but to the actual module file of the page where we want to add the calendar. In our app we already got the default page so let’s simply add it to the app/home/home.module.ts like:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { IonicModule } from '@ionic/angular'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { HomePage } from './home.page'; import { NgCalendarModule } from 'ionic2-calendar'; @NgModule({ imports: [ CommonModule, FormsModule, IonicModule, RouterModule.forChild([ { path: '', component: HomePage } ]), NgCalendarModule ], declarations: [HomePage] }) export class HomePageModule {}
There are no further imports for dates or whatsoever right now and we can dive right into it!
Creating the Calendar View
The first part of our view consists of a bunch of elements that we need to control the calendar and add new events.
We can control different aspects of the calendar, for example:
Set the view to focus today
Change the mode of the calendar which changes the view to month/week/day
Move our calendar view forward/back
Also we add a little card to create a new event to our calendar because it will be pretty empty. You can also take a look at the demo code which uses a random events function to fill your calendar for testing!
All of these things are not really essential and the important part is at the end of our view: The actual calendar component!
On this component we can set a lot of models and functions and the best way to explore all of them is the options of the package.
You will see what the functions do and what’s used once we move on to the class, so for now just open your app/home/home.page.html and change it to:
<ion-header> <ion-toolbar color="primary"> <ion-title> </ion-title> <ion-buttons slot="end"> <ion-button (click)="today()">Today</ion-button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> <!-- Card for adding a new event --> <ion-card> <ion-card-header tappable (click)="collapseCard = !collapseCard"> <ion-card-title>New Event</ion-card-title> </ion-card-header> <ion-card-content *ngIf="!collapseCard"> <ion-item> <ion-input type="text" placeholder="Title" [(ngModel)]="event.title"></ion-input> </ion-item> <ion-item> <ion-input type="text" placeholder="Description" [(ngModel)]="event.desc"></ion-input> </ion-item> <ion-item> <ion-label>Start</ion-label> <ion-datetime displayFormat="MM/DD/YYYY HH:mm" pickerFormat="MMM D:HH:mm" [(ngModel)]="event.startTime" [min]="minDate"></ion-datetime> </ion-item> <ion-item> <ion-label>End</ion-label> <ion-datetime displayFormat="MM/DD/YYYY HH:mm" pickerFormat="MMM D:HH:mm" [(ngModel)]="event.endTime" [min]="minDate"></ion-datetime> </ion-item> <ion-item> <ion-label>All Day?</ion-label> <ion-checkbox [(ngModel)]="event.allDay"></ion-checkbox> </ion-item> <ion-button fill="outline" expand="block" (click)="addEvent()" [disabled]="event.title == ''">Add Event</ion-button> </ion-card-content> </ion-card> <ion-row> <!-- Change the displayed calendar mode --> <ion-col size="4"> <ion-button expand="block" [color]="calendar.mode == 'month' ? 'primary' : 'secondary'" (click)="changeMode('month')">Month</ion-button> </ion-col> <ion-col size="4"> <ion-button expand="block" [color]="calendar.mode == 'week' ? 'primary' : 'secondary'" (click)="changeMode('week')">Week</ion-button> </ion-col> <ion-col size="4"> <ion-button expand="block" [color]="calendar.mode == 'day' ? 'primary' : 'secondary'" (click)="changeMode('day')">Day</ion-button> </ion-col> <!-- Move back one screen of the slides --> <ion-col size="6" text-left> <ion-button fill="clear" (click)="back()"> <ion-icon name="arrow-back" slot="icon-only"></ion-icon> </ion-button> </ion-col> <!-- Move forward one screen of the slides --> <ion-col size="6" text-right> <ion-button fill="clear" (click)="next()"> <ion-icon name="arrow-forward" slot="icon-only"></ion-icon> </ion-button> </ion-col> </ion-row> <calendar [eventSource]="eventSource" [calendarMode]="calendar.mode" [currentDate]="calendar.currentDate" (onEventSelected)="onEventSelected($event)" (onTitleChanged)="onViewTitleChanged($event)" (onTimeSelected)="onTimeSelected($event)" startHour="6" endHour="20" step="30" startingDayWeek="1"> </calendar> </ion-content>
The only fixed properties we have set are these:
startHour/endHour: Pretty self explanatory, right?
step: How detailed the hour blocks will be divided in the week/day view
startingDayWeek: Welcome all US friends, in Germany the week starts on Monday so put a 0 or 1 here whatever you prefer
Now we need to put some logic behind all of this.
Note: We are using the calendar in its basic version. By now there’s really a lot you can customise, especially by using custom templates for cells and different other slots that you can easily add. If it doesn’t do the job immediately for you try to play around with these elements to make it fit your needs.
Adding the Calendar Logic
We start with the basics for adding new events. For this we will keep an array eventSource that we also previously connected to the calendar.
If you have an API where you pull the data from, you gonna add the data to this source as well!
Also, normally the events only consists of a title, the times and an all day flag but actually you can have more info in there like a description, id or whatever – you will see that it get’s passed through when you click on an even later.
We also have to make some date transformation as the ion-datetime expects an ISO string for the date while the calendar wants it to be a Date object.
Finally, if the new event should be an all day event we have to manually patch the starting and end times using a little transformation as well.
Now go ahead with the first part of your app/home/home.page.ts:
import { CalendarComponent } from 'ionic2-calendar/calendar'; import { Component, ViewChild, OnInit, Inject, LOCALE_ID } from '@angular/core'; import { AlertController } from '@ionic/angular'; import { formatDate } from '@angular/common'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { event = { title: '', desc: '', startTime: '', endTime: '', allDay: false }; minDate = new Date().toISOString(); eventSource = []; viewTitle; calendar = { mode: 'month', currentDate: new Date(), }; @ViewChild(CalendarComponent) myCal: CalendarComponent; constructor(private alertCtrl: AlertController, @Inject(LOCALE_ID) private locale: string) { } ngOnInit() { this.resetEvent(); } resetEvent() { this.event = { title: '', desc: '', startTime: new Date().toISOString(), endTime: new Date().toISOString(), allDay: false }; } // Create the right event format and reload source addEvent() { let eventCopy = { title: this.event.title, startTime: new Date(this.event.startTime), endTime: new Date(this.event.endTime), allDay: this.event.allDay, desc: this.event.desc } if (eventCopy.allDay) { let start = eventCopy.startTime; let end = eventCopy.endTime; eventCopy.startTime = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate())); eventCopy.endTime = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate() + 1)); } this.eventSource.push(eventCopy); this.myCal.loadEvents(); this.resetEvent(); } }
Now we are already able to add events to the calendar, but we also need some more functions that we connected inside the view previously.
Let’s talk about the them real quick so we can finish our basic calendar implementation:
next/back: Manually change the view (which normally works by swiping) using the underlying Swiper instance because the calendar uses Ionic Slides
changeMode: Change between the month/week/day views
today: Focus back to the current date inside the calendar
onViewTitleChanged: The view changed and the title is automatic updated
Next to these basic functionality we also receive the click event when we select an event inside the calendar.
As said before, here we get the full object from our source so if you use some API data you now got the ID and can easily show the details for an event. In our case we use the Angular date pie from code to transform the dates and then just present an alert for testing.
Finally whenever you click on a time slot in the calendar the onTimeSelected will be triggered and we use it to set the current start and end date of our event.
Normally you might want to immediately open an overlay to create a new event when a user clicks on a time slot like they are used to from Google or Apple calendar! We also have to make sure to use ISO strings for the date again at this point because of the component we used.
Now wrap up everything by adding these functions below your existing code inside the app/home/home.page.ts but of course still inside the class:
// Change current month/week/day next() { var swiper = document.querySelector('.swiper-container')['swiper']; swiper.slideNext(); } back() { var swiper = document.querySelector('.swiper-container')['swiper']; swiper.slidePrev(); } // Change between month/week/day changeMode(mode) { this.calendar.mode = mode; } // Focus today today() { this.calendar.currentDate = new Date(); } // Selected date reange and hence title changed onViewTitleChanged(title) { this.viewTitle = title; } // Calendar event was clicked async onEventSelected(event) { // Use Angular date pipe for conversion let start = formatDate(event.startTime, 'medium', this.locale); let end = formatDate(event.endTime, 'medium', this.locale); const alert = await this.alertCtrl.create({ header: event.title, subHeader: event.desc, message: 'From: ' + start + '<br><br>To: ' + end, buttons: ['OK'] }); alert.present(); } // Time slot was clicked onTimeSelected(ev) { let selected = new Date(ev.selectedTime); this.event.startTime = selected.toISOString(); selected.setHours(selected.getHours() + 1); this.event.endTime = (selected.toISOString()); }
You now got a fully functional calendar with a lot of ways to customise the appearance and react to user input and different events!
Conclusion
The Ionic2-calendar package remains one of the best ways to add a calendar to your Ionic app fast. If you depend on drag & drop functionality you still have to look somewhere else as this is not yet included (maybe in the future?).
Have you used a better calendar inside your Ionic app yet?
Let me know your experiences in the comments!
You can also find a video version of this article below.
The post How to Build an Ionic 4 Calendar App appeared first on Devdactic.
via Devdactic https://ift.tt/2UJknmd
0 notes
Text
Building a Notepad Application from Scratch with Ionic
A difficult part of the beginner’s journey to learning Ionic is the step between understanding some of the basics and actually building a fully working application for the first time. Concepts explained in isolation can make sense, but it may be difficult to understand when to use them in the context of building an application. Even after spending some time learning about Ionic, you might find yourself starting a new project with no idea where to begin.
The aim of this tutorial is to provide a complete walkthrough of building a simple (but not too simple) Ionic application from start to finish. I have attempted to strike a balance between optimised/best-practice code, and something that is just straight-forward and easy enough for beginners to understand. Sometimes the “best” way to do things can look a lot more complex and intimidating, and doesn’t serve much of a purpose for beginners. You can always introduce more advanced concepts to your code as you continue to learn.
I will be making it a point to take longer to explain smaller concepts in this tutorial, more so than others, since it is targeted at people right at the beginning of their Ionic journey. However, I will not be able to cover everything in the level of depth required. I will mostly be including just enough to introduce you to the concept in this tutorial, and I will link out to further resources to explain those concepts in more depth.
What will we be building?
The example we will be building needs to be simple enough such that it won’t take too much effort to build, but it also needs to be complex enough to be a realistic representation of a real application.
I decided on building a notepad application for this example, as it will allow us to cover many of the core concepts such as:
Navigation/Routing
Templates
Two-way data binding
Interpolations
Event binding
Types and Interfaces
Services
Data Input
Data Storage
Styling
As well as covering important concepts, it is also a reasonably simple and fun application to build. In the end, we will have something that looks like this:
We will have an application that allows us to:
Create, delete, and edit notes
Save and load those notes from storage
View a list of notes
View note details
Before We Get Started
Last updated for Ionic 4, beta.7
This tutorial will assume that you have read at least some introductory content about Ionic, have a general understanding of what it is, and that you have Ionic set up on your machine. You will also need to have a basic understanding of HTML, CSS, and JavaScript.
If you do not already have Ionic set up on your machine, or you don’t have a basic understanding of the structure of an Ionic project, take a look at the additional resource below for a video walkthrough.
Additional resources:
Installing Ionic and Basic Project Structure
1. Generate a New Ionic Project
Time to get started! To begin, we will need to generate a new Ionic 4 application. We can do that with the following command:
ionic start ionic-notepad blank --type=angular
We are naming our application ionic-notepad and we are using the blank template from Ionic (which will just give us a bare-bones starter template). By supplying the --type flag we are indicating we want to create an Ionic/Angular project (which will generate an Ionic 4 application for us).
You will be prompted to set up Cordova or Ionic Pro during the creation process, you can just say no to these. Once the application has finished generating, make it your working directory by running:
cd ionic-notepad
2. Create the Required Pages/Services
This application will have two pages:
Home (a list of all notes)
Detail (the details of a particular note)
and we will also be making use of a service/provider:
NotesService
which is going to be responsible for handling most of the logic around creating, updating, and deleting notes. We are going to create these now by using Ionic’s generate command.
Run the following commands to generate the pages:
ionic g page Home
ionic g page Detail
Run the following commands to generate the service:
ionic g service services/Notes
The reason we use services/Notes instead of just Notes is that we want all of our services to be within a services folder (by default, they will just be created in the project root directory).
3. Setting up Navigation/Routing
Now we move on to our first real bit of work – setting up the routes for the application. Most of this is handled automatically for us when we generate the pages, but we are going to make a couple of changes.
Modify src/app/app-routing.module.ts to reflect the following:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'notes', pathMatch: 'full' }, { path: 'notes', loadChildren: './home/home.module#HomePageModule' }, { path: 'notes/:id', loadChildren: './detail/detail.module#DetailPageModule' }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
We’ve renamed out home path to notes just because I think it makes more sense for the URL to say notes – this is purely a cosmetic change. We have also changed the path for our Detail page to:
notes/:id
This is not just a cosmetic change. By adding :id to the path, which is prefixed by a colon : we are creating a route that will accept parameters which we will be able to grab later. That means that if a user goes to the following URL:
http://localhost:8100/notes
They will be taken to the Home page. However, if they go to:
http://localhost:8100/notes/12
They will be taken to the Detail page, and from that page, we will be able to grab the :id value of 12. We will make use of that id to display the appropriate note to the user later.
Additional resources:
Angular Routing in Ionic
4. Starting the Notes/Home Page
The Home page, which will display a list of all of the notes the user has added, will be the default screen that user sees. We are going to start implementing the template for this page now. We don’t have everything in place that we need to complete it, so we will just be focusing on getting the basic template set up.
Modify src/app/home/home.page.html to reflect the following:
<ion-header> <ion-toolbar color="primary"> <ion-title> Notes </ion-title> <ion-buttons slot="end"> <ion-button> <ion-icon slot="icon-only" name="clipboard"></ion-icon> </ion-button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> <ion-list> <ion-item button detail> <ion-label>Title goes here</ion-label> </ion-item> </ion-list> </ion-content>
This template is entirely made up of Ionic’s web components. We have the <ion-header> which contains the title for our page, and we have <ion-buttons> set up inside of the <ion-toolbar> which will allow us to place a set of buttons either to the left or the right of the toolbar. In this case, we just have a single button in the end slot which we are using as the button to trigger adding a new note. By giving our icon a slot of icon-only it will style the icon so that it is larger (since it doesn’t have text accompanying it).
Then we have our <ion-content> section which provides the main scrolling content section of the page. This contains an <ion-list> with a single <ion-item>. Later, we will modify this list to create multiple items – one for each of the notes that are currently stored in the application.
There will be more information available about all of this, including “slots”, in the additional resources at the end of this section.
Although we will not be making any major changes to the class for our Home page just yet, let’s change a few minor things and talk through the code that is there already.
Modify src/app/home/home.page.ts to reflect the following:
import { Component, OnInit } from '@angular/core'; import { AlertController, NavController } from '@ionic/angular'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { constructor(private alertCtrl: AlertController, private navCtrl: NavController){ } ngOnInit(){ } }
At the top, we have our imports – these are the dependencies that we will need to make use of in this page. We import Component and OnInit from the @angular/core library, and we import AlertController and NavController from the @ionic/angular library.
Component allows us to create a component using the @Component decorator and specifies the metadata for the page including the URL of its template and .scss file (required for all components/pages)
OnInit allows us to implement the ngOnInit method which will be triggered as soon as the page is initialised
AlertController will allow us to create alert prompts
NavController will allow us to control navigation using Ionic’s navigation methods
It isn’t enough to just import some of these dependencies, we also may need to set them up in our class using dependency injection. We need to “inject” these dependencies through the constructor in the class. Take a look at the following code:
constructor(private alertCtrl: AlertController, private navCtrl: NavController){ }
What this is doing is setting up class members, which will be references to the injected dependency, that will be accessible through the class. In the case of the AlertController we are basically saying:
“Create a class member variable called alertCtrl which will be an instance of the AlertController service”
By prefixing this with private we are saying that we want this variable to be accessible anywhere inside of this class (but not outside of the class). We could also use public which would make the variable accessible anywhere inside or outside of the class.
This means that anywhere in this class we will be able to reference this.alertCtrl or this.navCtrl to access the methods that they each provide.
It’s going to be hard for us to go much further than this without starting to work on our Notes service, as this is what is going to allow us to add, update, and delete notes. Without it, we don’t have anything to display!
Additional resources:
Understanding Slots
An Introduction to ES6 Modules for Ionic Developers
Angular Concepts & Syntax
5. Creating an Interface
Before we implement our Notes service, we are going to define exactly “what” a note is by creating our own custom type with an interface.
Angular uses TypeScript, which is basically JavaScript with “types”. A type gives us a way to enforce that data is what we expect it to be, and you will often see variables, methods, and parameters followed by a colon : and then a type. For example:
let myName: string = "Josh"
Since we have added : string after the variable we defined, it will enforce that myName can only be a string. If we tried to assign a number to myName it wouldn’t allow us to do it. I don’t want to dive too deep into types and interfaces here, so I will link to another tutorial in the additional resources section.
Create a folder and file at src/app/interfaces/note.ts and add the following:
export interface Note { id: string, title: string, content: string }
This will allow us to import a Note type elsewhere in our application, which will allow us to force our notes to follow the format defined above. Each note must have an id that is a string, a title that is a string, and content that is a string.
Additional resources:
Creating Custom Interfaces
6. Implement the Notices Service
The pages in our application are responsible for displaying views/templates on the screen to the user. Although they are able to implement logic of their own in their associates *.page.ts files, the majority of the complex logic performed in our applications should be done in services.
A service does not display anything to the user, it is just a “helper” that is used by components/pages in our application to perform logic/data operations. Our pages can then call the methods of this service to do work for it. This way, we can keep the code for our pages light, and we can also share the data and methods available through services with multiple pages in our application (whereas, if we define methods in our pages they are only accessible to that one page). Services are the primary way that we are able to share data between different pages.
Our Notes service will implement various methods which will allow it to:
Create a note and add it to an array in the data service
Delete notes from that array
Find and return a specific note by its id
Save the array of notes to storage
Load the array of notes from storage
Let’s implement the code, and then talk through it. I’ve added comments to various parts of the code itself, but we will also talk through it below.
import { Injectable } from '@angular/core'; import { Storage } from '@ionic/storage'; import { Note } from '../interfaces/note'; @Injectable({ providedIn: 'root' }) export class NotesService { public notes: Note[] = []; public loaded: boolean = false; constructor(private storage: Storage) { } load(): Promise<boolean> { // Return a promise so that we know when this operation has completed return new Promise((resolve) => { // Get the notes that were saved into storage this.storage.get('notes').then((notes) => { // Only set this.notes to the returned value if there were values stored if(notes != null){ this.notes = notes; } // This allows us to check if the data has been loaded in or not this.loaded = true; resolve(true); }); }); } save(): void { // Save the current array of notes to storage this.storage.set('notes', this.notes); } getNote(id): Note { // Return the note that has an id matching the id passed in return this.notes.find(note => note.id === id); } createNote(title): void { // Create a unique id that is one larger than the current largest id let id = Math.max(...this.notes.map(note => parseInt(note.id)), 0) + 1; this.notes.push({ id: id.toString(), title: title, content: '' }); this.save(); } deleteNote(note): void { // Get the index in the array of the note that was passed in let index = this.notes.indexOf(note); // Delete that element of the array and resave the data if(index > -1){ this.notes.splice(index, 1); this.save(); } } }
Once again, we have our imports at the top of the file. Rather than Component we use Injectable this time, which provides the @Injectable decorator we use with all of our services/providers. This allows us to define where the service is providedIn which in this case (and in most cases) is root, meaning that a single instance of this service will be available for use throughout our entire application.
We also import Storage which we inject through the constructor as we will be making use of it to save and load data throughout the service, and we also import our Note interface that we just created.
We set up two class members above our constructor:
notes which will be an array of notes (the Note[] type means it will be an array of our Note type we created)
loaded which is a boolean (true or false) which will indicate whether or not the data has been loaded in from storage
Like the dependencies we inject through the constructor, variables declared above the constructor will be accessible throughout the entire class using this.notes or this.loaded.
IMPORTANT: We will be making use of this.storage throughout this class, but it won’t work until we complete the next step. There are additional dependencies that need to be installed for storage.
Our load function is responsible for loading data in from storage (if it exists) and then setting it up on the this.notes array. We surround this entire method with a Promise that resolves when the operation is complete, as we will need a way to detect when the operation has finished later. This is asynchronous behaviour, and it is critically important to understand the difference between asynchronous and synchronous code – I’ve linked to further information on this in the additional resources at the end of this section.
The way in which we are loading data in this application I would describe as a “beginner friendly” approach. There are “better” ways to do this using observables, but this is a perfectly acceptable approach.
The save function simply sets our notes array on the notes key in storage so that it can be retrieved later – we will call this whenever there is a change in data.
The getNote function will accept an id, it will then search through the notes array and return the note that matches the id passed in. We will make use of this in our detail page later.
The createNote function handles creating a new note and pushing it into the notes array. We do have an odd bit of code here:
let id = Math.max(...this.notes.map(note => parseInt(note.id)), 0) + 1;
We need each of our notes to have a unique id so that we can grab them appropriately through the URL. To keep things simple, we are using a simple numeric id (an id could be anything, as long as it is unique). To ensure that we always get a unique id, we use this code to find the note with the largest id that is currently in the array, and then we just add 1 to that.
Finally, the deleteNote method simply takes in a note and then removes that note from the array.
Additional resources:
Asynchronous vs Synchronous: Understanding the Difference
Navigation Basics & Passing Data Between Pages in Ionic & Angular
When & How to Use Services/Providers in Ionic
7. Setting up Data Storage
Ionic provides a useful Storage API that will automatically handle storing data using the best mechanism available. However, it is not installed by default. To set up Ionic Storage, you will first need to install the following package:
npm install @ionic/storage --save
You will also need to make a change to your root module file.
Modify src/app/app.module.ts to reflect the following:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule, RouteReuseStrategy, Routes } from '@angular/router'; import { IonicStorageModule } from '@ionic/storage'; 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'; @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, IonicStorageModule.forRoot()], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {}
Notice that we have imported IonicStorageModule from @ionic/storage and we have added IonicStorageModule.forRoot() to the imports for the module.
Additional resources:
Ionic Storage API
An Introduction to NgModule for Ionic
8. Finishing the Notes Page
With our notes service in place, we can now finish off our Home page. We will need to make some modifications to both the class and the template.
Modify src/app/home/home.page.ts to reflect the following:
import { Component, OnInit } from '@angular/core'; import { AlertController, NavController } from '@ionic/angular'; import { NotesService } from '../services/notes.service'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { constructor(private notesService: NotesService, private alertCtrl: AlertController, private navCtrl: NavController){ } ngOnInit(){ this.notesService.load(); } addNote(){ this.alertCtrl.create({ header: 'New Note', message: 'What should the title of this note be?', inputs: [ { type: 'text', name: 'title' } ], buttons: [ { text: 'Cancel' }, { text: 'Save', handler: (data) => { this.notesService.createNote(data.title); } } ] }).then((alert) => { alert.present(); }); } }
We have added one additional import which is the NotesService. Just like the services we import from the Ionic library, we also need to inject our own service through the constructor to make it available to use throughout this component.
We have added a call to the load method of the Notes service, which will handle loading in the data from storage as soon as the application is started.
We have also added an addNote() method which will allow the user to add a new note. We will create an event binding in the template later to tie a button click to this method, which will launch an Alert on screen. This prompt will allow the user to enter a title for their new note, and when they click Save the new note will be added.
Now we just need to finish off the template.
Modify src/app/home/home.page.html to reflect the following:
<ion-header> <ion-toolbar color="primary"> <ion-title> Notes </ion-title> <ion-buttons slot="end"> <ion-button (click)="addNote()"> <ion-icon slot="icon-only" name="clipboard"></ion-icon> </ion-button> </ion-buttons> </ion-toolbar> </ion-header> <ion-content> <ion-list> <ion-item button detail *ngFor="let note of notesService.notes" [href]="'/notes/' + note.id" routerDirection="forward"> <ion-label></ion-label> </ion-item> </ion-list> </ion-content>
We have modified our button in the header section to include a click event binding that is linked to the addNote() method. This will trigger the addNote() method we just created whenever the user clicks on the button.
We have also modified our notes list:
<ion-list> <ion-item button detail *ngFor="let note of notesService.notes" [href]="'/notes/' + note.id" routerDirection="forward"> <ion-label></ion-label> </ion-item> </ion-list>
Rather than just having a single item, we are now using *ngFor which will loop over each note in our notes array in the notes service (which is why we reference notesService.notes).
Take notice of the * syntax used here for the *ngFor in the list, this is shorthand for creating an embedded template. Rather than literally rendering out:
<ion-item button detail *ngFor="let note of notesService.notes">
to the DOM (Document Object Model), an embedded template will be created for each items specific data. So, if our notes array had 4 notes in it, then the via joshmorony - Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2y5WScQ
0 notes
Text
Touch ID iOS Tutorial
Touch ID refers to the fingerprint sensor built into the home button of iPhone TouchID is based on the Local Authentication framework. In this tutorial touch ID authentication will be implemented and the user is presented with an Alert View if the authentication does/doesn’t succeed. This tutorial is made with Xcode 10 and built for iOS 12.
Open Xcode and create a new Single View App.
For product name, use IOSTouchIDTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Go to the Storyboard and drag a Button to the main view. Set the title of the button to Authenticate. Select the Resolve Auto Layout Issues button and select Reset to Suggested Constraints.
The Storyboard should look like this.
Select the Assistant Editor and make sure the ViewController.swift is visible. Ctrl and drag from the Button to the ViewController class and create the following Action
As the Touch ID is based on the Local Authentication framework it needs to be imported to the project. Go to the ViewController.swift file and add the following line
import LocalAuthentication
Next add a helper method to display messages in a Alert Controller.
func showAlertController(_ message: String) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) present(alertController, animated: true, completion: nil) }
A message and a OK button is added to the Alert Controller and it will be presented. Next implement the authWithTouchID method
@IBAction func authWithTouchID(_ sender: Any) { // 1 let context = LAContext() var error: NSError? // 2 // check if Touch ID is available if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { // 3 let reason = "Authenticate with Touch ID" context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason, reply: {(success, error) in // 4 if success { self.showAlertController("Touch ID Authentication Succeeded") } else { self.showAlertController("Touch ID Authentication Failed") } }) } // 5 else { showAlertController("Touch ID not available") } }
Get the authentication context from the Local Authentication framework
The canEvaluatePolicy method checks if Touch ID is available on the device
The policy is evaluated where the third parameter is a completion handler block.
An Alert message is shown wether the Touch ID authentication succeeded or not
If Touch ID is not available an Alert message is shown.
Build and Run the project, this must be done on a real device, since the Simulator doesn't have Touch ID functionality.
Activate the Touch ID. When it succeeds the following alert will show.
You can download the source code of the IOSTouchIDTutorial at the ioscreator repository on Github.
0 notes
Text
Detect Long Press Gesture iOS Tutorial
Long-press gestures are a type of a continuous gesture. UIKit will detect if a press is pushed long instead of a single tap. In this tutorial a long-press gesture is detected, which will display an an alert view. This tutorial is made with Xcode 10 and built for iOS 12.
Open Xcode and create a new Single View App.
For product name, use IOSLongPressGestureTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Go to the Storyboard and drag a Button to the main view. Set the title of the button to "Press me". Select the Resolve Auto Layout Issues button and select Reset to Suggested Constraints.
Drag a Long Press Gesture Recognizer from the Object Library on top of the Button. The Storyboard should look like this.
Select the Assistant Editor and make sure the ViewController.swift is visible. Ctrl and drag from the Long Press Gesture Recognizer to the ViewController class and create the following Action
Ctrl and drag from the Long Press Gesture Recogniser to the Button and select delegate. The button will now detect the long press gesture.
Go to the ViewController.swift file and implement the handleGesture method
@IBAction func handleGesture(_ sender: UILongPressGestureRecognizer) { if sender.state == .began { let alertController = UIAlertController(title: nil, message: "Long-Press Gesture Detected", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "OK", style: .default,handler: nil)) present(alertController, animated: true, completion: nil) } }
The began UIRecognizerState is a continuous state. If this is recognised an Alert View is Presented. Build and Run the project and long press on the Press me Button.
You can download the source code of the IOSLongPressGestureTutorial at the ioscreator repository on Github.
0 notes
Text
Display Alert iOS Tutorial
A UIAlertController object displays an alert message to the user. This class replaces the UIActionSheet and UIAlertView classes for displaying alerts. In this tutorial we will display an alert when the user clicks a button. This tutorial is made with Xcode 10 and built for iOS 12.
Open Xcode and create a new Single View App.
For product name, use IOSDisplayAlertTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Go to the Storyboard and drag a Button to the main View. Double-click the button and give it a title of "Display Alert". Select the button and click the Pin Auto Layout button on the bottom-right of the Storyboard. Pin the button at the top edge and select "Items of New Constraints" at the Update Frames section. Select "Add 1 Constraint".
Select the button and click the Align Auto Layout button. Select the "Horizontally in Container" checkbox and select "Items of New Constraints" at the Update Frames section. Select "Add 1 Constraint".
Select the Assistant Editor and open ViewController.swift. Ctrl-drag or right-click-drag from the Button to the class and create the following Action.
Next, implement the showAlert function.
@IBAction func showAlert(_ sender: Any) { let alertController = UIAlertController(title: "iOScreator", message: "Hello, world!", preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Dismiss", style: .default)) self.present(alertController, animated: true, completion: nil) }
The alertController constant is assigned an UIAlertController object. Since we will show an Alert the preferredStyle is set to alert. The alertController is then presented modally with the present(_:animated:completion:) method. Build and Run the project and press the Display Alert button to display the alert.
You can download the source code of the IOSDisplayAlertTutorial at the ioscreator repository on github.
0 notes
Text
Editable Text Field inside Alert Controller iOS Tutorial
Using the UIAlertController class it is not only possible to show alerts, but also get text input using Text Fields. In this tutorial a username and password is obtained from the user and displayed in the console. This tutorial is made with Xcode 10 and built for iOS 12.
Open Xcode and create a new Single View App.
For product name, use IOSTextFieldAlertControllerTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and choose Next.
Go to the Storyboard. Drag a Button from the Object Library to the top of the main View. Double-click the Button and set the title to "Log in". Ctrl + Drag to the top of the main view and select the "Vertical Spacing to Top Layout Guide" and "Center Horizontally in Container". options.
The Storyboard should look like this.
Select the Assistant Editor and make sure the ViewController.swift is visible. Ctrl and drag from the Button and create the following Action.
Inside the ViewController class, implement the showAlertController action method.
@IBAction func showAlertController(_ sender: Any) { // 1. var usernameTextField: UITextField? var passwordTextField: UITextField? // 2. let alertController = UIAlertController( title: "Log in", message: "Please enter your credentials", preferredStyle: .alert) // 3. let loginAction = UIAlertAction( title: "Log in", style: .default) { (action) -> Void in if let username = usernameTextField?.text { print(" Username = \(username)") } else { print("No Username entered") } if let password = passwordTextField?.text { print("Password = \(password)") } else { print("No password entered") } } // 4. alertController.addTextField { (txtUsername) -> Void in usernameTextField = txtUsername usernameTextField!.placeholder = "<Your username here>" } alertController.addTextField { (txtPassword) -> Void in passwordTextField = txtPassword passwordTextField?.isSecureTextEntry = true passwordTextField?.placeholder = "<Your password here>" } // 5. alertController.addAction(loginAction) present(alertController, animated: true, completion: nil) }
Two optional variables are declared to represent the two textfields inside the Alert
An Alert Controller with the Alert style is created
An Alert Action is created, inside the closure the entered text in the Text Fields will be printed to the console.
The addTextField method adds the text input fields, taking the Text Field as a parameter inside the closure.
The login action is added to the Alert Controller and the controller is displayed.
Build and Run the project. Select the login button and fill in the username/password field inside the Alert Controller. The entered text will be displayed in the console.
You can download the source code of the IOSTextFieldAlertControllerTutorial at the ioscreator repository on Github.
0 notes
Text
Creating Ionic Datatable With ngx-datatable
If you are working with a lot of data you might have encountered the problem of presenting this data in an Excel like way inside your Ionic app. Although the datatable pattern is not always the most recommended for mobile apps, especially in times of PWAs having the ability to create a table within your Ionic app is a great alternative.
Inside this tutorial we will use the ngx-datatable package which was made for Angular apps, so we can perfectly use this inside our Ionic app as well!
But as you can see from the gif above, using this pattern on small devices is problematic but let’s talk about the good things for now and see how to add it to our app.
Adding ngx-datatable to your Ionic Project
Like always we start with a blank Ionic app and install the datatable packe to our app, so go ahead and run:
ionic start dataTable blank
cd dataTable
npm i @swimlane/ngx-datatable
ionic g page table
We’ve also created a new page which comes with a module file, because the initial page doesn’t. Therefore, go ahead and remove all references to the HomePage from your module file and then set a new entry point for our app inside the app/app.component.ts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = 'TablePage';
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
});
}
}
The ngx-datatable comes with some predefined styling we can use, but first we need to make sure the styling and an additional font is copied over to our build folder. Therefore, add a new block to your package.json
"config": {
"ionic_sass": "./config/sass.config.js",
"ionic_copy": "./config/copy.config.js"
}
We've changed the copy times already in many other articles, and the only change we really need is to copy over the fonts in an additional task. Create the folder and new file at config/copy.config.js and insert everything from the regular Ionic copy script plus a block which copies over the fonts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {
copyAssets: {
src: ['/assets/**/*'],
dest: '/assets'
},
copyIndexContent: {
src: ['/index.html', '/manifest.json', '/service-worker.js'],
dest: ''
},
copyFonts: {
src: ['/node_modules/ionicons/dist/fonts/**/*', '/node_modules/ionic-angular/fonts/**/*'],
dest: '/assets/fonts'
},
copyPolyfills: {
src: ['/node_modules/ionic-angular/polyfills/polyfills.js'],
dest: ''
},
copyNgxFont: {
src: ['/node_modules/@swimlane/ngx-datatable/release/assets/fonts/data-table.ttf',
'/node_modules/@swimlane/ngx-datatable/release/assets/fonts/data-table.woff'],
dest: '/fonts'
}
}
For the second special file, create another new file at config/sass.config.js. For this file, copy the contents of the original file (which is pretty long) from /node_modules/@ionic/app-scripts/config/sass.config.js.
Then, search for the includePaths block and add one line to it at the end like this:
includePaths: [
'node_modules/ionic-angular/themes',
'node_modules/ionicons/dist/scss',
'node_modules/ionic-angular/fonts',
'node_modules/@swimlane/ngx-datatable/release'
],
Now both the font and styling of the package is copied to our build folder and we can use it easily! To make the styling available to our app we also need to import both available styles, so change your app/app.scss to:
@import 'themes/bootstrap';
@import 'themes/dark';
@import 'assets/icons';
That’s all for the integration, now to the actual usage!
Presenting a Basic Table
We start with a super basic example where we’ll display some information in the most easy way possible.
To use this package inside your pages you first need to add it to the imports of the module, in our case we need to change the pages/table/table.module.ts to this:
import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { TablePage } from './table';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
@NgModule({
declarations: [
TablePage,
],
imports: [
IonicPageModule.forChild(TablePage),
NgxDatatableModule
],
})
export class TablePageModule {}
Next we need some data which I’ve copied from one of their examples.
Additionally I’ve already incorporated a little switch so you can change the theme of your datatable from bootstrap to dark so you can see both of them in action!
There’s not much to it right now, so change your pages/table/table.ts to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage()
@Component({
selector: 'page-table',
templateUrl: 'table.html',
})
export class TablePage {
// https://ift.tt/2L4O4cI
rows = [
{
"name": "Ethel Price",
"gender": "female",
"age": 22
},
{
"name": "Claudine Neal",
"gender": "female",
"age": 55
},
{
"name": "Beryl Rice",
"gender": "female",
"age": 67
},
{
"name": "Simon Grimm",
"gender": "male",
"age": 28
}
];
tablestyle = 'bootstrap';
constructor(public navCtrl: NavController, public navParams: NavParams) { }
switchStyle() {
if (this.tablestyle == 'dark') {
this.tablestyle = 'bootstrap';
} else {
this.tablestyle = 'dark';
}
}
}
We wanted to build the most basic version of a table first, so here it is! We only add one extra button to change our table style, and inside the view we craft the table.
This table needs rows which are the datasource and even the additional attributes I’ve adde might be obsolete but are needed to present the table in an appealing way on a mobile device.
Inside the table you then define columns for your values, in our case three of them which will look up the value of their name. The name doesn’t have to be the key inside the array, but more on this later.
The table will now iterate over your data and create the according rows and columns, so for now change the pages/table/table.html to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ion-header>
<ion-navbar color="dark">
<ion-title>ngx-Table</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="switchStyle()">
<ion-icon name="bulb"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ngx-datatable class="fullscreen" [ngClass]="tablestyle" [rows]="rows" [columnMode]="'force'" [sortType]="'multi'" [reorderable]="false">
<ngx-datatable-column name="Name"></ngx-datatable-column>
<ngx-datatable-column name="Gender"></ngx-datatable-column>
<ngx-datatable-column name="Age"></ngx-datatable-column>
</ngx-datatable>
</ion-content>
The result of this simple is what you can see below.
Kinda nice for just a few lines of HTML that create everything from a given datasource, right?
Advanced Ionic Datatable
Let’s build a more sophisticated example with some reordering mechanism, additional row buttons and special styling.
For this, we start by adding a few functions to our class. To determine a special class that get’s added to a row we define the getRowClass() function that checks if the dataset of the row is a male or female person. In both cases we return the name of a CSS class that we will define later.
When we open a row, we simply present an alert with basic information gathered from the row to show how everyhting works.
Finally we also have some summary functions that can be used to display a summary row inside your table. Most of the time the default summary for your column won’t work so with these functions you can write your own logic for creating the sum or average or whatever you want to display!
In our case we present the sum of male/female persons as well as the average age of our persons.
Go ahead and add the new functions to your pages/table/table.ts like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, AlertController } from 'ionic-angular';
@IonicPage()
@Component({
selector: 'page-table',
templateUrl: 'table.html',
})
export class TablePage {
// https://ift.tt/2L4O4cI
rows = [
{
"name": "Ethel Price",
"gender": "female",
"age": 22
},
{
"name": "Claudine Neal",
"gender": "female",
"age": 55
},
{
"name": "Beryl Rice",
"gender": "female",
"age": 67
},
{
"name": "Simon Grimm",
"gender": "male",
"age": 28
}
];
tablestyle = 'bootstrap';
constructor(public navCtrl: NavController, public navParams: NavParams, private alertCtrl: AlertController) { }
switchStyle() {
if (this.tablestyle == 'dark') {
this.tablestyle = 'bootstrap';
} else {
this.tablestyle = 'dark';
}
}
getRowClass(row) {
return row.gender == 'male' ? 'male-row' : 'female-row';
}
open(row) {
let alert = this.alertCtrl.create({
title: 'Row',
message: `${row.name} is ${row.age} years old!`,
buttons: ['OK']
});
alert.present();
}
//
// Summary Functions
//
genderSummary(values) {
let male = values.filter(val => val == 'male').length;
let female = values.filter(val => val == 'female').length;
return `${male} / ${female}`;
}
ageSummary(values) {
return values.reduce((a, b) => a+b, 0) / values.length;
}
}
Now we also need to add some changes to the view in order to make use of the new functionality we’ve implemented. First of all we add the CSS that is needed to customize rows based on the gender, so change your pages/table/table.scss to:
page-table {
.male-row {
background-color: green !important;
}
.female-row {
background-color: red !important;
}
}
The last missing piece now is the view which needs to be changed for our custom columns. We’ve previously seen basic columns, but we can also have more control about the header, the used value for the column or which summary function should be used.
There are quite a few options you can set for both the table and columns, so for all the information check out the official documentation which also contains examples for almost everything the package offers!
Let’s change the code and talk about a few elements afterwards, so open your pages/table/table.html and change it to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<ion-header>
<ion-navbar color="dark">
<ion-title>ngx-Table</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="switchStyle()">
<ion-icon name="bulb"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ngx-datatable class="fullscreen" [ngClass]="tablestyle" [rows]="rows" [columnMode]="'force'" [sortType]="'multi'" [reorderable]="false"
[rowHeight]="50" [rowClass]="getRowClass" [summaryRow]="true" [summaryPosition]="'top'">
<ngx-datatable-column prop="name" [resizeable]="false">
<ng-template let-column="column" ngx-datatable-header-template let-sort="sortFn">
<span (click)="sort()">Special User</span>
</ng-template>
<ng-template let-value="value" ngx-datatable-cell-template>
{{ value }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Gender" [summaryFunc]="genderSummary.bind(this)"></ngx-datatable-column>
<ngx-datatable-column name="Age" [summaryFunc]="ageSummary.bind(this)"></ngx-datatable-column>
<ngx-datatable-column name="id" [resizeable]="false">
<ng-template ngx-datatable-header-template>
Action
</ng-template>
<ng-template let-row="row" ngx-datatable-cell-template>
<button ion-button small outline color="light" (click)="open(row)">Details</button>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</ion-content>
Here is a bit more information about what we’ve used and what it does:
let-sort=”sortFn”: Use the default alpha numeric ordering mechanism for this column
prop: Use the specified key inside the datasource to lookup the value for the column
summaryFunc: Use a special summary function for the whole column
.bind(this): Not needed here but makes this available inside the function called!
let-value=”value”: Makes the value of the column available as value
let-row=”row”: Make the whole row object available inside the column
As said before, there’s really a lot you can customize and some elements won’t work that well together. In my testing, the now applied summary function actually breaks the reordering mechanism, but I’m sure there is some fix for that issue as well.
Conclusion
Overall you should be careful when you use a table inside a mobile app, but if you decide you need one the ngx-datatable is an awesome package that offers a lot of options to customize how your data is presented!
You can also find a video version of this article below.
youtube
Get the free 7 day Ionic Crash Course to learn how to:
Get started with Ionic
Build a Tab Bar navigation
Make HTTP calls to a REST API
Store Data inside your app
Use Cordova plugins
Style your Ionic app
The course is free, so there's nothing you can lose!
Success! Now check your email to confirm your subscription.
via Devdactic https://ift.tt/2NHzXfh
0 notes
Text
Creating a Flash Message Service in Ionic
You will often run into circumstances in your application where you want to send some kind of alert to the user. You might want to let them know that they have lost their Internet connection, or that a post failed to upload, or that a photo has finished successfully uploading. In terms of the built-in Ionic components, you could use the AlertController to fulfill this role. However, it does require a little work to set up the alert, and you may not always want to use that style of overlay alert:
In this tutorial, we are going to create a flash message component and service that will allow us to trigger the following code anywhere in our application:
this.flashProvider.show('Base is under attack!', 2000)
This will display a message at the top of the screen for 2000ms that will look like this:
It will be overlayed at the top of the application, so you don’t need to worry too much about integrating it into different types of layouts – it should just work everywhere. As you can tell from the GIF above, we are animating this overlay in and out, and we are using the Angular animations library to achieve that.
There are some pre-built libraries you could use to achieve this, but we are going to build our own for the sake of learning. I also think it is generally a good idea to roll your own solution if you just require something simple. Pre-made libraries are usually very extensive and cover a range of use cases you probably won’t need.
Before We Get Started
Last updated for Ionic 3.9.2
Before you go through this tutorial, you should have at least a basic understanding of Ionic concepts. You must also already have Ionic set up on your machine.
If you’re not familiar with Ionic already, I’d recommend reading my Ionic Beginners Guide first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic, then take a look at Building Mobile Apps with Ionic.
1. Create a New Ionic Application
Let’s get started by generating a new Ionic application, and setting up the component and provider that we will need.
Generate a new Ionic application:
ionic start ionic-flash-message blank
Run the following commands to generate the component and provider:
ionic g component Flash
ionic g provider Flash
The FlashComponent will be the component that is displayed on screen when we trigger a flash message, and the FlashProvider is what we will use to interact with that component anywhere in our application. The way in which we will do this is actually pretty cool and interesting.
In order to be able to use the Flash component throughout the application, we need to make sure to add the components module to the app.module.ts file, and we also need to set up the provider.
Modify src/app/app.module.ts to reflect the following:
import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { SplashScreen } from '@ionic-native/splash-screen'; import { StatusBar } from '@ionic-native/status-bar'; import { ComponentsModule } from '../components/components.module'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { FlashProvider } from '../providers/flash/flash'; @NgModule({ declarations: [ MyApp, HomePage ], imports: [ BrowserModule, ComponentsModule, IonicModule.forRoot(MyApp) ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler}, FlashProvider ] }) export class AppModule {}
If you are unfamiliar with how custom components work, I have a basic tutorial explaining custom components here. If you are interested in a much more advanced look at custom components, an entire module in the Elite Ionic course is dedicated to it.
2. Implement the Flash Messages Component
First, we are going to set up the component that we want to display. We will need to design the template, styling, and animations for the component, and we will also need to implement the methods to control the display and hiding of the component.
I’m not going to be covering how the Angular animations library works in-depth here, we are just going to quickly walk through the steps to set it up – I will assume that you are already somewhat familiar with it. If you would like some more background on Angular animations I would recommend checking out these tutorials: Add to Cart with the Web Animations API in Ionic & Animating from the Void: Enter and Exit Animations in Ionic.
Install the Angular Animations library:
npm install @angular/animations --save
Install the Web Animations API polyfill:
npm install web-animations-js --save
Modify src/app/main.ts to reflect the following:
import 'web-animations-js/web-animations.min'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
Modify src/components/components.module.ts to reflect the following:
import { NgModule } from '@angular/core'; import { FlashComponent } from './flash/flash'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ declarations: [FlashComponent], imports: [ BrowserModule, BrowserAnimationsModule ], exports: [FlashComponent] }) export class ComponentsModule {}
With that set up, we can get to work on creating the component itself.
Modify src/components/flash/flash.html to reflect the following:
<div (click)="hide()" @messageState *ngIf="active" class="flash-container"> <div class="message"> </div> </div>
The template for this component is reasonably simple. We toggle the component in and out of the DOM by attaching the active class member to an *ngIf directive. This way, when we set active to true it will display, and when we set active to false it won’t. We have the @messageState animation trigger attached to the container as well, which we will use to set up the animation. We also have an event binding set up for hide() so that a user will also be able to tap on the message to dismiss it, rather than waiting for it to timeout.
Next, we are going to set up the class for the component. This will handle the logic for displaying and hiding the flash message, and it will also set up the entry and exit animations.
Modify src/components/flash/flash.ts to reflect the following:
import { Component } from '@angular/core'; import { FlashProvider } from '../../providers/flash/flash'; import { trigger, state, style, animate, transition } from '@angular/animations'; @Component({ selector: 'flash', templateUrl: 'flash.html', animations: [ trigger('messageState', [ transition('void => *', [ style({transform: 'translateY(-100%)'}), animate('200ms ease-out') ]), transition('* => void', [ animate('200ms ease-in', style({opacity: '0'})) ]) ]) ] }) export class FlashComponent { active: boolean = false; message: string = ''; constructor(private flashProvider: FlashProvider) { this.flashProvider.show = this.show.bind(this); this.flashProvider.hide = this.hide.bind(this); } show(message, duration){ this.message = message; this.active = true; setTimeout(() => { this.active = false; }, duration); } hide(){ this.active = false; } }
If the animations that we have set up above don’t make sense to you, make sure to check out the tutorial that I mentioned before.
The hide and show functions are reasonably straight-forward – these just handle setting the message and toggling the active status. The interesting part of this component is what we are doing in the constructor:
constructor(private flashProvider: FlashProvider) { this.flashProvider.show = this.show.bind(this); this.flashProvider.hide = this.hide.bind(this); }
This is the same technique that this flash messages package uses, and I think it is a fantastic pattern. We are importing the FlashProvider (which we haven’t finished implementing yet) and then we are overriding its methods in the constructor. The flash provider will have the same show and hide functions, and we are binding those to the scope of our flash component. This might be a little confusing so let me walk through the concept a little more.
Our FlashProvider is a singleton service (meaning that there is one instance of it created for the entire application) that can be accessed from anywhere in the application. This is great for our requirements of a flash message because we could call a show method on it from anywhere in the application. However, providers don’t have an associated view/template, so that makes it a little more difficult for us to add the component to the DOM.
Our FlashComponent allows us to easily create the template for our component and interact with that component with various methods, but we can’t easily access the methods of this component anywhere in our application like we can with the provider.
What we are doing in this constructor is binding the show and hide methods in the provider, to the show and hide methods in the component. This means that whenever we call show in our provider, it will actually be calling show in the component. This is what allows us to trigger the showing and hiding of the flash message from anywhere in the application.
Finally, we just need to add a little styling to the component.
Modify src/components/flash/flash.scss to reflect the following:
flash { .flash-container { position: absolute; top: 0; width: 100%; height: 56px; color: #fff; background-color: #ff7675; border: 1px solid #d63031; z-index: 1; display: flex; align-items: center; justify-content: center; } }
We are using absolute positioning at the top of the application so that we don’t really need to worry about how the element is going to interact with the rest of the layout.
3. Implement the Flash Messages Service
In the last section, we bound the methods of our provider to the methods in our component. We don’t actually need to do much to our FlashProvider but we do need to define the methods that we are calling.
Modify src/providers/flash/flash.ts to reflect the following:
import { Injectable } from '@angular/core'; @Injectable() export class FlashProvider { constructor() { } show(message, duration){ } hide(){ } }
We don’t need to add any logic in here because it is the method in the component that is actually being called, but the functions do still need to be defined so that we can reference them.
4. Use the Flash Messages Service
Now that we have everything set up, we just need to use our new service. Before we can do that, we need to make sure to add the flash component into our root components template.
Modify src/app/app.html to reflect the following:
<flash></flash> <ion-nav [root]="rootPage"></ion-nav>
Once you have made that change, you will be able to import the flash provider and trigger a flash message from anywhere. Let’s walk through a quick example.
Modify src/pages/home/home.html to reflect the following:
<ion-header> <ion-navbar color="primary"> <ion-title> Flash Messages </ion-title> <ion-buttons end> <button ion-button icon-only><ion-icon name="add"></ion-icon></button> </ion-buttons> </ion-navbar> </ion-header> <ion-content padding> <button ion-button (click)="testFlash()">Test Flash</button> </ion-content>
Modify src/pages/home/home.ts to reflect the following:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { FlashProvider } from '../../providers/flash/flash'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { constructor(public navCtrl: NavController, private flashProvider: FlashProvider) { } ionViewDidLoad(){ } testFlash(){ this.flashProvider.show('Base is under attack!', 2000); } }
You should now be able to click the test button and see a message that looks like this:
Summary
Now with just a couple lines of code, you can trigger a flash message from anywhere in your application. You could customise this component to look or function however you like. This is just a really simple example, but you might want to integrate some options for determining different types of messages (e.g. warning, success, info, and so on). Perhaps you may want to improve the UI a bit by adding a close button or an indicator of how long the message will remain displayed. You could even trigger additional actions when the message is tapped based on the kind of message that is being displayed.
There is a lot you could do with this component, but I think the basic structure of it is super cool as it is extremely easy to integrate into your application.
via joshmorony – Build Mobile Apps with HTML5 http://ift.tt/2okffpH
0 notes
Text
Customizing Ionic Apps for Web & Mobile
This is a guest post from Simon Grimm, speaker and educator at Ionic Academy. Simon writes about Ionic frequently on his blog Devdactic.
With the development of Ionic apps comes the promise that your code will run on various platforms and screen sizes once it’s ready. While this can work and look fine on your targeted devices out of the box, it might not at first for everyone.
In this post, we’ll take a look at 4 areas to keep an eye on – especially if you plan to ship your Ionic app both as a website (or perhaps PWA?) and also as a native mobile app (perhaps even on phone and tablet devices).
Everything we need is already built into Ionic, but sometimes it’s easy to forget about all the awesomeness. So let’s get started with a tiny base for our examples!
App Starting Template Setup
For this article run the command below to start a new Ionic app with the side menu template:
ionic start devdacticResponsive sideMenu
It’s a super basic app with just 2 pages and a side menu (otherwise the name would be kinda bad) but we also need to make HTTP calls, therefore we use the new HttpClient which is available since Angular 5 and Ionic 3.9.0.
Simply change your app/app.module.ts to:
import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { HomePage } from '../pages/home/home'; import { ListPage } from '../pages/list/list'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ MyApp, HomePage, ListPage ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), HttpClientModule ], bootstrap: [IonicApp], entryComponents: [ MyApp, HomePage, ListPage ], providers: [ StatusBar, SplashScreen, {provide: ErrorHandler, useClass: IonicErrorHandler} ] }) export class AppModule {}
That’s all we’ll need for our examples, so now let’s dive into our areas.
1. Responsive Grid Layout
Most Ionic components already adapt to screen changes and look good across various sizes. However, having something like a list item full size or an Ionic Card displayed full width on my large iMac screen kills my eyes.
If you need your app to look good on a small device and in a desktop web browser, you’ll need to make it as responsive as possible. And what’s better then using the Ionic Grid layout system?
But first we need some data we can display inside a list, so let’s add a simple HTTP call to your pages/home/home.ts like this:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { Observable } from 'rxjs/Observable'; import { HttpClient } from '@angular/common/http'; import "rxjs/add/operator/map"; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { users: Observable<any>; constructor(public navCtrl: NavController, private httpClient: HttpClient, private plt: Platform, private alertCtrl: AlertController) { this.users = this.httpClient.get('https://randomuser.me/api/?results=20') .map(res => res['results']) } }
Now we have an array of users from the Randomuser API which we can display as cards. You could make this as simple iteration without any further testing, but if you’re serious about your design (which, of course you are!), you’ll want to make sure to test different sizes and breakpoints.
A breakpoint is a predefined value at which your design snaps from one category to the next. If your screen is smaller than 576px, you fall into the smallest category which is xs. However, at 577px your design will get the sm category applied, so you must prepare your design to also look good there, and at later breakpoints as well.
With Ionic, we can use the row and column system plus the breakpoints to build interfaces that look great across different platforms and adapt to display the best and most intuitive interface to the user.
Let’s take our example and add this code to our pages/home/home.html:
<ion-header> <ion-navbar> <button ion-button menuToggle> <ion-icon name="menu"></ion-icon> </button> <ion-title>Home</ion-title> </ion-navbar> </ion-header> <ion-content> <ion-grid> <ion-row> <ion-col *ngFor="let user of users | async" col-12 col-xl-2 col-lg-3 col-md-4> <ion-card> <ion-item> <ion-avatar item-start> <img [src]="user.picture.medium"> </ion-avatar> <h2 text-capitalize> </h2> </ion-item> <ion-card-content> Bacon ipsum dolor amet salami prosciutto ham hock, strip steak buffalo ribeye pork chop. Beef ribs tenderloin tail shoulder. Spare ribs ham shoulder brisket rump hamburger. Pork belly kevin shoulder prosciutto ribeye pork chop chicken strip steak pig. </ion-card-content> </ion-card> </ion-col> </ion-row> </ion-grid> </ion-content>
One Ionic row offers 12 units space for columns, so each column can take an amount of those 12. If your row takes 12 units, it means the row is already full and the next column will be displayed in the following row.
The syntax for the column isn’t immediately obvious, so let’s dive deeper into what it actually means:
col-12: If no other rules match, the column will take all 12 units (greedy column!)
col-md-4: At a minimum width of 768px, each column will only use 4 units. This means, a row can now handle 3 columns
col-lg-3: As the screen gets bigger than 992px, a column only needs 3 units which means the row how holds 4 columns
col-xl-2: On the largest screens (1200px+), a column only needs 2 units and a row will display 6 columns
In our example, a column always holds a card, so the design ranges from seeing only 1 card to 6 cards maximum (seen below).
Using a decent flexible layout is definitely mandatory if your app is going to run on multiple platforms and screen sizes. If you don’t invest time into doing this, your app might scare off potential users because it just looks odd.
There’s a lot more to the Grid like setting your own breakpoints, reordering columns, and more so go check it out!
2. CSS Media Queries
While we can’t really accredit this one directly to Ionic, we are still lucky that Ionic bets strongly on the Web and we can thus take advantage of languages like CSS, which most of us have all learned years ago.
Just like the grid layout, we can make use of breakpoints here as well by using @media and different sizes to change part of our UI.
In a recent app, we needed an ion-fabbutton at the top right corner on the web version as it was too hard to spot when it was at the far bottom right corner. However, on a mobile version of your app users are already familiar with having the button floating above lists at the bottom right.
This means the element needs exist in completely different places depending on screen size (and this is a simple element).
One way to achieve this is by having the element there twice, but only displaying it when the media query of your CSS matches. To do this, add the Fab button to your your pages/home/home.html after the list we already have:
<ion-fab right bottom class="web-fab"> <button ion-fab icon-only color="primary" (click)="checkPlatform()"> <ion-icon name="help"></ion-icon> </button> </ion-fab> <ion-fab right top edge class="mobile-fab"> <button ion-fab icon-only color="primary" (click)="checkPlatform()"> <ion-icon name="help"></ion-icon> </button> </ion-fab>
If you want to make only one button visible, you could use the follow CSS inside your pages/home/home.scss:
page-home { @media (max-width: 576px) { ion-card-content { font-size: 2rem !important; } } @media (max-width: 820px) { .mobile-fab { display: none; } } @media (min-width: 820px) { .web-fab { display: none; } } }
By using the media query you can of course do much more than hide and show elements by repositioning your elements. If you know where your elements should be exactly on the screen, you can also use just one element with the class.
For this example I wanted to use the Ionic values right bottom and top edge therefore I added the element twice instead of manually setting the position of the button.
With media queries you can customize the complete UI up to using a completely different UI for phone and tablet devices. It’s good to have this tool in your toolbox.
3. Checking Your Platform
Not only do we have to think about the UI of our app on different platforms, we should also understand on which platform(s) our app is running.
If your app runs inside a regular desktop browser you don’t need to call the Push notification setup, and you especially don’t want to make any calls to Cordova when running as a website!
To prevent this, simply inject the Platform whenever you need it and create checks to see on which platform you are running. As a test, open your pages/home/home.ts and change it to:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { Observable } from 'rxjs/Observable'; import { HttpClient } from '@angular/common/http'; import "rxjs/add/operator/map"; import { Platform } from 'ionic-angular/platform/platform'; import { AlertController } from 'ionic-angular/components/alert/alert-controller'; @Component({ selector: 'page-home', templateUrl: 'home.html' }) export class HomePage { users: Observable<any>; constructor(public navCtrl: NavController, private httpClient: HttpClient, private plt: Platform, private alertCtrl: AlertController) { this.users = this.httpClient.get('https://randomuser.me/api/?results=20') .map(res => res['results']) } checkPlatform() { let alert = this.alertCtrl.create({ title: 'Platform', message: 'You are running on: ' + this.plt.platforms(), buttons: ['OK'] }); alert.present(); if (this.plt.is('cordova')) { // Do Cordova stuff } else { // Do stuff inside the regular browser } } }
By checking this.plt.is('cordova') you can be sure that Cordova is available to your app, but you could also test for iOS / Android if you have specific code for those platforms.
One feature that’s especially different on a device and desktop browser is files. Inside your native app you will have a completely different file object (most of the time path to your app) then when you implement file upload for a browser.
If your app doesn’t need the feature on one or the other platform, no problem! But be aware that you have to keep an eye on testing your features on all targeted platforms to make sure everything’s working as planned.
4. Ionic Split Pane
One feature thing that makes desktop UI ready in seconds is the Ionic Split Pane.
We’ve already started an app with a side menu, so we only need to apply minimal changes to achieve a flexible dynamic UI that adapts to the screen size and automatically shows / hides our side menu.
Combine this approach with some CSS, and you get a (more or less) great looking web UI for your app. Don’t hate my color choices, this example is not about how I never became the designer I dreamed to be.
So here’s what you need to change for your Split Pane inside the app/app.html:
<ion-split-pane when="sm"> <ion-menu [content]="content"> <ion-header> <ion-toolbar color="secondary"> <ion-title>Menu</ion-title> </ion-toolbar> </ion-header> <ion-content class="menu-container"> <ion-list no-lines> <button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)" class="transparent list-item"> </button> </ion-list> </ion-content> </ion-menu> <!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus --> <ion-nav [root]="rootPage" #content main swipeBackEnabled="false"></ion-nav> </ion-split-pane>
With the side menu template, our menu is directly at the top of the app. Normally this would be perhaps in a later page (after a login) and therefore also the CSS would be in a different place.
For this example, we have to fit our additional CSS into the app/app.scss with some colors and changes to make the menu look more natural on the web:
.split-pane-side { border-right: 0px !important; } .menu-container { background-color: color($colors, secondary); } .transparent { background: transparent; } .list-item { color: #ffffff; margin-bottom: 10px; font-size: 2rem; } :hover.list-item { background: #2e8015; } .scroll-content{ overflow: hidden; margin-right: -17px; overflow-y: scroll; }
The standard UI doesn’t look that good for a website, but of course with some CSS, colors, and hover effects (which you don’t really need for a mobile app) you can make the menu look like a standard menu you’re familiar with.
To further customise your Split Pane, you can override Ionic variables inside the theme/variables.scss so simply add this:
$split-pane-side-max-width: 12%;
Now your side menu won’t expand too far, and even look nice even on big screens!
Conclusion
It’s already epic to have one code base that can be built into a native mobile app and also be deployed to the web, but the flexibility of using some CSS and responsive items makes Ionic the perfect choice for both your next web application, PWA and mobile app!
To learn more about everything Ionic, check out the Ionic Academy, which offers a ton of courses on all related topics, projects to apply your knowledge in, and also a dedicated community with help for all your questions!
Good luck, and happy building!
via The Official Ionic Blog http://ift.tt/2CdrMA5
0 notes