how to show data of model.ts in my code, using ionic 2 - ionic-framework

now i trying array data modeling using ionic2.
i created 'model.ts' in 'src/app/models' and declared in 'setting.ts' with array data.
next, i called it to 'setting.html'.
By the way...There is a some problem.
build and run were success. but any datas didn't show in screen..
not Error, i dont know where is wrong..
please find wrong point and fix that.
there is my code..
workoutlist-model.ts
export class WorkoutlistModel {
constructor(public Workoutlist: any[]) {
this.Workoutlist = [];
}
addItem(nm, gl) {
this.Workoutlist.push({
name: nm,
goal: gl
});
}
removeItem(nm, gl) {
for (var i = 0; i < this.Workoutlist.length; i++) {
if (this.Workoutlist[i].name == nm) {
if (this.Workoutlist[i].goal == gl) {
this.Workoutlist.splice(i);
}
}
}
}
}
setting.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { WorkoutlistModel } from '../../app/models/workoutlist-model';
#Component({
selector: 'page-setting',
templateUrl: 'setting.html'
})
export class Setting {
constructor(public navCtrl: NavController) {
new WorkoutlistModel([{ name: 'Push-Up', goal: 100 },
{ name: 'Squat', goal: 150 },
{ name: 'Sit-Up', goal: 45 }]);
}
}
setting.html - the part using this.
<ion-content style="height: 200px; outline: green">
<ion-card *ngFor="let WO of WorkoutlistModel;">
<button ion-item>
<div style="float: left;padding: 0px;">name : {{WO.name}}</div>
<div style="float: right;padding: 0px;">goal : {{WO.goal}}</div>
</button>
</ion-card>
</ion-content>

You havent declared or assigned WorkoutlistModel
Also WorklistModel is class and not an array to traverse with *ngFor
export class Setting {
workListModel:any;//declare
constructor(public navCtrl: NavController) {
this.workListModel = new WorkoutlistModel([{ name: 'Push-Up', goal: 100 },
{ name: 'Squat', goal: 150 },
{ name: 'Sit-Up', goal: 45 }]);//assign
}
}
In Html
<ion-card *ngFor="let WO of workListModel.getList();"><!-- get the list of items from class to traverse. may have to create this function -->
<button ion-item>
<div style="float: left;padding: 0px;">name : {{WO.name}}</div>
<div style="float: right;padding: 0px;">goal : {{WO.goal}}</div>
</button>
</ion-card>

You are not injecting the model. So change it to this.
constructor( Workoutlist: any[]) {
this.Workoutlist = Workoutlist;
}

Related

IONIC 4 : getActiveIndex() is not working in ion-slides

Using IONIC 4 ion-slides, I am trying to get currently clicked silde index using getActiveIndex() as below which it is not working.
<ion-slides #testSlider (ionSlideTap)="getIndex()">
<ion-slide>....</ion-slide>
</ion-slides>
#ViewChild('testSlider') slider: ElementRef; // first way
getIndex() {
this.slider.nativeElement.getActiveIndex();
}
#ViewChild('testSlider') slider: Slider; //second way
getIndex() {
this.slider.getActiveIndex();
}
And the another way as below which is also not working:
<ion-slides #testSlider (ionSlideTap)="getIndex(testSlider)">
<ion-slide>....</ion-slide>
</ion-slides>
getIndex(testSlider) {
testSlider.getActiveIndex();
}
Can anyone please suggest me how can I get active index or currently clicked slide index in IONIC 4 ?
I had the same problem, but managed to solve it as follows:
export class SomePage implements OnInit {
...
currentIndex:Number = 0;
...
getSlideIndex(){
this.slides.getActiveIndex().then(
(index)=>{
this.currentIndex = index;
});
}
...
this.getSlideIndex();
console.log(this.currentIndex);
Note that although it seems to work, I suspect that because the value is changes inside promise, it will only return the correct value if it has not recently changed. I thus intend to update this with a wait implemented to counter this.
in template
<ion-slides pager="true" (ionSlideDidChange)="slideChanged($event)" #slides>
</ion-slides>
in component
import { IonSlides } from '#ionic/angular';
#ViewChild('slides', {static: true}) slides: IonSlides;
slideChanged(e: any) {
this.slides.getActiveIndex().then((index: number) => {
console.log(index);
});
}
According to the documentation, getActiveIndex() returns a Promise<number>.
So by using ionSlideTap:
<ion-slides (ionSlideTap)="onSlideTapped($event)">
...
</ion-slides>
I found two ways to do it:
As phunder suggests, you can use then() to retrieve its value. I also did it with async/await:
async onSlideTapped(event: any) {
const index: number = await event.target.getActiveIndex();
console.log(index);
}
Or you can use the swiper object:
onSlideTapped(event: any) {
console.log(event.target.swiper.clickedIndex);
}
Therefore, you don't have to listen for every changes or to import the IonSlides in your component.
UPDATED:
I think I made a few mistakes, here is working example (Ionic 3). Please make sure you are using $event.
Template file:
<ion-slides (ionSlideTap)="getIndex($event)">
<ion-slide>1</ion-slide>
</ion-slides>
Now in TS file:
getIndex(event) {
console.log(event.clickedIndex);
}
Try the above approach?
Here is working stackblitz: https://stackblitz.com/edit/ionic-ssvout
1)Assign id to the respective like #slides
<div>
<ion-slides #slide (ionSlideDidChange)="SlideChanges(slide)">
</ion-slides>
</div>
2) import IonSlides in your.ts page/component
import { IonSlides } from '#ionic/angular';
3). Use method
SlideChanges(slide: IonSlides) {
slide.getActiveIndex().then((index: number) => {
this.yourSlideIndex= index;
alert(this.yourSlideIndex)
});
}
for ionic 4
*.html
<ion-slides #slides (ionSlideDidChange)="slideChanged(slides)">
...
</ion-slides>
*. ts
...
#ViewChild('slides', { static: false }) slides: IonSlides;
...
slideChanged(slides: IonSlides) {
slides.getActiveIndex().then((index: number) => {
console.log(index);
this.currentIndex = index;
});
}
Yes, It's working...!
// Typescript
import { IonSlides } from '#ionic/angular';
// in Component Class
export class AppComponent implements OnInit {
#ViewChild('contentSlider') contentSlider: IonSlides;
constructor(){}
ngOnInit() {}
do_getActiveSlide(e: any) {
this.contentSlider.getActiveIndex().then((index: number) => {
console.log("Current active slide index", index);
});
}
}
div {
width: 100%;
height: 5em;
color: gold;
background-color: #333;
margin: 1.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/#ionic/core/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/#ionic/core/dist/ionic/ionic.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#ionic/core/css/ionic.bundle.css"/>
<ion-slides pager="true" (ionSlideDidChange)="do_getActiveSlide($event)" #contentSlider>
<ion-slide>
<div>1</div>
</ion-slide>
<ion-slide>
<div>2</div>
</ion-slide>
<ion-slide>
<div>3</div>
</ion-slide>
</ion-slides>

This.username is undefined in ionViewDidLoad() but defined in ionViewWillLeave() - Ionic3 chat mobile application

I'm trying to create a simple chat application with Ionic 3 and Firebase. Registering, logging in users, sending and displaying their messages work. This is a common chat room for all users.
I'd like a message to appear in the chat room when a user is logged in or logged out to let other users know. When test user is logged in, this message appears: "has joined the room"
When test user is logged out, this message appears: "test#gmail.com has left the room"
I'd like the username (email address) to show when the user is logged in as well. I'd like this message to appear: "test#gmail.com has joined the room"
I tried write this.username on the console, but it only writes this to the console: ionViewDidLoad ChatPage. The username doesn't appear on the console:
console.log('ionViewDidLoad ChatPage', this.username);
chat.ts:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import { Storage } from '#ionic/storage';
import { Subscription } from 'rxjs/Subscription';
import $ from 'jquery';
#IonicPage()
#Component({
selector: 'page-chat',
templateUrl: 'chat.html',
})
export class ChatPage {
username: string= '';
message: string= '';
obsRef: AngularFireObject<any>;
obsToData: Subscription;
messages: object[]= [];
constructor(public db: AngularFireDatabase, public navCtrl: NavController, public navParams: NavParams, private storage: Storage) {
this.storage.get('username').then((val) => {
if (val != null) {
this.username= val;
}
});
this.obsRef = this.db.object('/chat');
this.obsToData = this.obsRef.valueChanges().subscribe( data => {
var data_array= $.map(data, function(value, index) {
return [value];
});
this.messages= data_array;
});
}
sendMessage() {
this.db.list('/chat').push({
username: this.username,
message: this.message
}).then( () => {
this.message= '';
});
}
ionViewWillLeave() {
console.log('user is about to go');
this.obsToData.unsubscribe();
this.db.list('/chat').push({
specialMessage: true,
message: this.username + `has joined the room`
})
}
ionViewDidLoad() {
console.log('ionViewDidLoad ChatPage', this.username);
this.db.list('/chat').push({
specialMessage: true,
message: this.username + `has joined the room`
})
}
}
chat.html:
<ion-header>
<ion-navbar>
<ion-title>Chat</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<div id="chatMessages">
<div *ngFor="let message of messages" [class]="message.specialMessage ? 'message special': 'message'">
<div [class]="message.username == username ? 'innerMessage messageRight': 'innerMessage messageLeft'">
<div class="username"> {{ message.username }} </div>
<div class="messageContent"> {{ message.message }} </div>
</div>
</div>
</div>
</ion-content>
<ion-footer>
<div id="footer">
<ion-input type="text" [(ngModel)]= "message"> </ion-input>
<button ion-button icon-only (click)= "sendMessage()">
<ion-icon name="send"></ion-icon>
</button>
</div>
</ion-footer>
Looking at your code, you are getting the username from Storage.
That is an Async operation, which means it can happen before or after ionViewLoad event.
this means in the following lines
this.storage.get('username').then((val) => {
if (val != null) { // this will run later
this.username= val;
}
the constructor will exist without anything in the 'then' being executed. those lines will run later whenever the storage has the results ready.
think of it as putting an order for data. Just because you have put in the order, does not mean your order has arrived.
looks like by the time you leave the view, the call to storage has finished and username is set.
I suggest you wait somehow for the username to arrive like
<div id="chatMessages" *ngIf="username?.length > 0">
And even better that that, refactor your code so that you have username ready by the time you get to this view. after all this view is not usable without having a username ready.
I doubt you are using a tabbed layout. If that is the case, then try getting the stored result using ionViewDidEnter() so that everytime you enter the page the result gets updated. Try doing something like this and check,
ionViewDidEnter(){
this.storage.get('username').then((val) => {
if (val != null) {
this.username= val;
}
});
}

ng-bootstrap Datepicker: Is there a way to select more than one date at once?

I'm in need of a calendar widget and, since I'm using Bootstrap 4 and ng-bootstrap in my current project, I'd like to know if the ng-boostrap widget support the multiselection of dates in some way.
I've already tried the wijmo Calendar for multiselection, but without success. Otherwise, can you recommend me a datepicker widget that has this capability?
This can help
<p>This datepicker uses a custom template to display days.</p>
<ngb-datepicker
[showWeekNumbers]="true"
[dayTemplate]="customDay"
(dateSelect)="selectOne($event)"
></ngb-datepicker>
<ng-template
#customDay
let-date
let-currentMonth="currentMonth"
let-selected="selected"
let-disabled="disabled"
let-focused="focused"
>
<span
class="custom-day"
[class.focused]="focused"
[class.bg-primary]="isSelected(date)"
>{{ date.day }}</span
>
</ng-template>
<div *ngIf="modelList.length>0">
<h1>Selected dates:</h1>
<pre>{{modelList| json}} </pre>
</div>
TypeScript
import { Component } from '#angular/core';
import {
NgbCalendar,
NgbDate,
NgbDateStruct,
} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'ngbd-datepicker-customday',
templateUrl: './datepicker-customday.html',
styles: [
`
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
display: inline-block;
width: 2rem;
}
.custom-day:hover, .custom-day.focused {
background-color: #e6e6e6;
}
.bg-primary {
border-radius: 1rem;
}
`,
],
})
export class NgbdDatepickerCustomday {
model: NgbDateStruct;
modelList: Array<NgbDateStruct> = [];
constructor(private calendar: NgbCalendar) {}
isSelected = (date: NgbDate) => {
return this.modelList.indexOf(date) >= 0;
};
selectOne(date) {
if (this.modelList.indexOf(date) >= 0) {
this.modelList = this.modelList.filter(function (ele) {
return ele != date;
});
} else {
this.modelList.push(date);
}
console.log(this.modelList);
}
}
Demo stackblitz
Yes, the ng-bootstrap datepicker supports range selection. You'll need to do manual conversion between the NgbDateStruct and a JavaScript Date object.

Ionic 3 Google Map does not display on Android + IOS

I use Ionic 3 version and I try to add a page into my app, to display a map with markers.
I already use for my app a Google Map Id for Autocomplete (Google places...).
I went to Google APIs and I added Map Embed, Javascript etc... to my API Key.
But The page appears with "Google" in the bottom and the display button", but the map is empty.
See attached file...
Install the Cordova and Ionic Native plugins:
$ ionic cordova plugin add https://github.com/mapsplugin/cordova-plugin-googlemaps#multiple_maps --variable API_KEY_FOR_ANDROID="AIzaSyB6mEnxH4vC+++++++++9wnXXNNmK2co" --variable API_KEY_FOR_IOS="AIzaSyB6mEnxH4v++++++++++++++wnXXNNmK2co"
$ npm install --save #ionic-native/google-maps
Home.ts:
import { NavController } from 'ionic-angular';
import { Component, ViewChild, ElementRef } from '#angular/core';
import { GoogleMaps, CameraPosition, GoogleMapsEvent, GoogleMap, MarkerOptions, Marker } from "#ionic-native/google-maps";
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild('map') mapElement: ElementRef;
map: any;
constructor(public navCtrl: NavController, private googleMaps: GoogleMaps) {
}
ngAfterViewInit() {
this.loadMap();
}
loadMap() {
// make sure to create following structure in your view.html file
// and add a height (for example 100%) to it, else the map won't be visible
// <ion-content>
// <div #map id="map" style="height:100%;"></div>
// </ion-content>
// create a new map by passing HTMLElement
let element: HTMLElement = document.getElementById('map');
let map: GoogleMap = this.googleMaps.create(element);
// listen to MAP_READY event
// You must wait for this event to fire before adding something to the map or modifying it in anyway
map.one(GoogleMapsEvent.MAP_READY).then(
() => {
console.log('Map is ready!');
// Now you can add elements to the map like the marker
}
);
// create CameraPosition
let position: CameraPosition = {
target: {
lat: 43.0741904,
lng: -89.3809802
},
zoom: 18,
tilt: 30
};
// move the map's camera to position
}
}
Home.HTML
Home.html :
<ion-header>
<ion-navbar>
<ion-title>
Map
</ion-title>
<ion-buttons end>
<button ion-button (click)="addMarker()"><ion-icon name="add"></ion-icon>Add Marker</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div #map id="map" style="height:100%;"></div>
</ion-content>
Home.scss
page-home {
}
Do not use the ngAfterViewInit.
You must wait platform.ready()
// Wait the native plugin is ready.
platform.ready().then(() => {
this.loadMap();
});
Full code is https://github.com/mapsplugin/cordova-plugin-googlemaps-doc/blob/master/v2.0.0/ionic-native/README.md
Repo: https://github.com/mapsplugin/ionic-google-maps
The current official document page is wrong. I sent a pull request, but it's waiting now.
https://github.com/ionic-team/ionic-native/pull/1834
Please try below code and make sure you are using correct API key, write following code in your .ts file:
ionViewDidLoad() {
this.loadMap();
}
loadMap() {
let mapOptions: GoogleMapOptions = {
camera: {
target: {
lat: 43.0741904,
lng: -89.3809802
},
zoom: 18,
tilt: 30
}
};
this.map = this.googleMaps.create('map_canvas', mapOptions);
// Wait the MAP_READY before using any methods.
this.map.one(GoogleMapsEvent.MAP_READY)
.then(() => {
console.log('Map is ready!');
this.map.addMarker({
title: 'Ionic',
icon: 'blue',
animation: 'DROP',
position: {
lat: 43.0741904,
lng: -89.3809802
}
})
.then(marker => {
marker.on(GoogleMapsEvent.MARKER_CLICK)
.subscribe(() => {
alert('clicked');
});
});
});
}
In your .html file define map like below
<ion-content>
<div id="map_canvas" style="height: 100%;"></div>
</ion-content>

How to use Bootstrap accordion with angular2 (HTML5 mode/hashbag in angular2)

I'm trying to use bootstrap accordion but both (angular2 and bootstrap accordian) plays around hash location.
So is there something like html5 mode in angular2?
try this
/// <reference path="../../../typings/tsd.d.ts" />
import {
Component, View,
Directive, LifecycleEvent,
EventEmitter, ElementRef,
CSSClass, ViewContainerRef, TemplateRef
} from 'angular2/angular2';
// todo: support template url
#Component({
selector: 'accordion, [accordion]',
properties: [
'templateUrl',
'bCloseOthers: closeOthers'
]
})
#View({
template: `
<div class="panel-group">
<ng-content></ng-content>
</div>
`
})
export class Accordion {
private templateUrl:string;
private bCloseOthers:any;
private groups:Array<any> = [];
constructor() {
}
public closeOthers(openGroup:AccordionGroup) {
if (!this.bCloseOthers) {
return;
}
this.groups.forEach((group:AccordionGroup) => {
if (group !== openGroup) {
group.isOpen = false;
}
});
}
public addGroup(group:AccordionGroup) {
this.groups.push(group);
}
public removeGroup(group:AccordionGroup) {
let index = this.groups.indexOf(group);
if (index !== -1) {
this.groups.slice(index, 1);
}
}
}
#Directive({
selector: 'accordion-transclude, [accordion-transclude]',
properties: ['headingTemplate: accordion-transclude'],
lifecycle: [LifecycleEvent.onInit]
})
export class AccordionTransclude {
private headingTemplate: TemplateRef;
constructor(private viewRef: ViewContainerRef) {
}
onInit() {
if (this.headingTemplate) {
this.viewRef.createEmbeddedView(this.headingTemplate);
}
}
}
import {Collapse} from '../collapse/collapse';
// todo: support template url
// todo: support custom `open class`
#Component({
selector: 'accordion-group, [accordion-group]',
properties: [
'templateUrl',
'heading',
'isOpen',
'isDisabled'
],
host: {
'[class.panel-open]': 'isOpen'
},
lifecycle: [LifecycleEvent.onInit, LifecycleEvent.onDestroy]
})
#View({
template: `
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a href tabindex="0" class="accordion-toggle"
(^click)="toggleOpen($event)">
<span [class]="{'text-muted': isDisabled}"
[accordion-transclude]="headingTemplate">{{heading}}</span>
</a>
</h4>
</div>
<div class="panel-collapse collapse" [collapse]="!isOpen">
<div class="panel-body">
<ng-content></ng-content>
</div>
</div>
</div>
`,
directives: [Collapse, AccordionTransclude, CSSClass]
})
export class AccordionGroup {
private templateUrl:string;
private _isOpen:boolean;
public isDisabled:boolean;
public headingTemplate:any;
public templateRef: any;
constructor(private accordion:Accordion) {
}
onInit() {
this.accordion.addGroup(this);
}
onDestroy() {
this.accordion.removeGroup(this);
}
public toggleOpen(event:MouseEvent) {
event.preventDefault();
if (!this.isDisabled) {
this.isOpen = !this.isOpen;
}
}
public get isOpen():boolean {
return this._isOpen;
}
public set isOpen(value:boolean) {
this._isOpen = value;
if (value) {
this.accordion.closeOthers(this);
}
}
}
#Directive({
selector: 'accordion-heading, [accordion-heading]'
})
export class AccordionHeading {
constructor(private group:AccordionGroup, private templateRef: TemplateRef) {
group.headingTemplate = templateRef;
}
}
export const accordion:Array<any> = [
Accordion, AccordionGroup,
AccordionHeading, AccordionTransclude];