Setting Style attributes of ionic2 component dynamically - html

What I'm trying to achieve:
<ion-header [style.background-color]="(style|async)?.logoBackground">
<ion-navbar >
<button ion-button icon-only menuToggle [style.background-color]="(style|async)?.menuButtonBackground">
<ion-icon name="menu"></ion-icon>
</button>
<ion-title [style.background-color]="(style|async)?.logoBackground">
<dynamic-logo [style]="style"></dynamic-logo>
</ion-title>
</ion-navbar>
</ion-header>
I have to reuse this code, over and over again.
"style" is a variable to an JSON object, I fetch dynamically which has the "style sheet for the app".
I'd lige to write it as simple as this, on other pages:
<dynamic-header [style]="style"></dynamic-header>
And having a component to set these (component appended below).
Though this is not possible in ionic2, because it'll wrap the <ion-header> in the <dynamic-header> and therefor not render the page correctly.
So I'm wondering if there is an alternative to making this as a component, maybe a way of making it as a Directive, I just havn't been able to find the necessary information about #Directive..
Also tried #Directive with binding <ion-content dynamic-content [style]="style">...</>
AND
[style]="(style|async)" gives WARNING: sanitizing unsafe style value [object Object] (see http://g.co/ng/security#xss).
TS:
import { Attribute, ChangeDetectionStrategy, Component, ElementRef, Input, Renderer, ViewEncapsulation } from '#angular/core';
import { PageStyle } from "../../providers/company-service";
#Component({
selector: 'dynamic-header',
templateUrl: 'dynamic-header.html',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class DynamicHeaderComponent {
#Input() style: PageStyle;
}
HTML:
<ion-header [style.background-color]="(style|async)?.logoBackground">
<ion-navbar >
<button ion-button icon-only menuToggle [style.background-color]="(style|async)?.menuButtonBackground">
<ion-icon name="menu"></ion-icon>
</button>
<ion-title [style.background-color]="(style|async)?.logoBackground">
<dynamic-logo [style]="style"></dynamic-logo>
</ion-title>
</ion-navbar>
</ion-header>
reformed to directive
import { Directive, HostBinding, Attribute, ChangeDetectionStrategy, Component, ElementRef, Input, Renderer, ViewEncapsulation } from '#angular/core';
import { PageStyle } from "../../providers/company-service";
#Directive({
selector: 'dynamic-content',
/* templateUrl: 'dynamic-content.html',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
*/
})
export class DynamicContentComponent {
#Input() style: PageStyle;
#HostBinding('style.background-image')
get getBackgroundImage() {
if (this.style) {
return this.style.backgroundImage;
}
}
#HostBinding('style.background-repeat')
get getBackgroundRepeat() {
if (this.style) {
return "no-repeat";
}
}
#HostBinding('style.background-size')
get getBackgroundSize() {
if (this.style) {
return "cover";
}
}
#HostBinding('style.color')
get getTextColor() {
if (this.style) {
return this.style.textColor;
}
}
}

From directives you can only bind single styles
export class DynamicHeaderComponent {
#Input() style: PageStyle;
// repeat this getter for every style property
#HostBinding('style.background-color')
get backgroundColor() {
if(this.style) {
return this.style.backgroundColor;
}
}
}

Related

ion date input with automatic submit upon selection

I'm new to ionic and I have this project that auto submits & shows reports when a date is selected. The problem is when I select a date the data isn't being submitted. Here is my .ts code.
async showRepo(item_date: Date) {
this.db.repoProduct(item_date).then((_) =>
{
console.log(_);
this.product = {};
});
}
And here is my .html code
<ion-item>
<ion-input
type="date"
(ionInput)='showRepo(item_date)'
></ion-input>
</ion-item>
Thanks in advance.
You can achieve this lot of ways. Create one variable and attach it with ion-input as a ngModel and use the ngModelChange event to catch the input change.
If you use the ion-datetime you can use the ionChange event to get the date change.
app.component.html
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Hello</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-item>
<ion-label>Pick date</ion-label>
<ion-input
value="{{ date | date: 'dd.MM.yyyy' }}"
id="date"
class="ion-text-end"
></ion-input>
<ion-popover
size="cover"
trigger="date"
show-backdrop="false"
[dismissOnSelect]="true"
>
<ng-template>
<ion-datetime
#popoverDatetime
presentation="date"
[(ngModel)]="date"
locale="en-US"
(ngModelChange)="pickDateModelChange($event)"
(ionChange)="ionChangeEvent(popoverDatetime.value)"
></ion-datetime>
</ng-template>
</ion-popover>
</ion-item>
</ion-content>
</ion-app>
app.component.ts
import { Component, OnInit } from '#angular/core';
import { AlertController } from '#ionic/angular';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
private dateValue: any;
get date(): any {
return this.dateValue;
}
set date(value: any) {
console.log({ value });
this.dateValue = value;
}
constructor() {}
ngOnInit() {}
pickDateModelChange(dateValue): void {
console.log('ngModel change triggered');
console.log(dateValue);
//here you need to add your date format function and service call
}
ionChangeEvent(date: Date): void {
console.log('ion change event triggered');
console.log(date);
//here you need to add your date format function and service call
}
}
working example is here

Cannot get ion-back-button to work properly

The ion-back-button I am trying to use on this page refuses to appear. There is nothing in the start slot when I should get a " < Back " button appearing.
selected_card.page.html
<ion-toolbar>
<ion-buttons slot='start'>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>{{restaurant.name}}</ion-title>
</ion-toolbar>
</ion-header>
selected_card.page.ts
import { ModalController, NavParams } from '#ionic/angular';
import { RestaurantsService } from '../services/restaurants.service';
#Component({
selector: 'app-selected-card',
templateUrl: './selected-card.page.html',
styleUrls: ['./selected-card.page.scss'],
})
export class SelectedCardPage implements OnInit {
// value: string;
restaurant: any;
constructor(private restaurantsService: RestaurantsService,
private modalCtrl: ModalController,
private navParams: NavParams) { }
ngOnInit() {
this.restaurant = this.navParams.get('restaurant');
console.log(this.restaurant);
}
selectRestaurant() {
console.log(this.customRestaurant)
this.customRestaurant()
}
dismiss() {
this.modalCtrl.dismiss();
}
}
Let me know if y'all have questions! Really cannot figure out why this will not work when it works every other time I use it.
I am not clear about your question though if you wanted ion-back-button you are not using this component inside your ion-buttons. ion-back-button should be used instead of ion-button ...
<ion-toolbar>
<ion-buttons slot='start'>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>{{restaurant.name}}</ion-title>
</ion-toolbar>
</ion-header>
This should work for showing back button.
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
Room info page
</ion-title>
</ion-toolbar>
</ion-header>

How to Vertical ion-item Scroll to Bottom and Top on Down and Up arrow icon button click in ionic 4?

I'm creating Ionic 4 plus Angular App, I want to add Up And Down Arrow
Button to Scroll Vertically Top To Bottom And Vice-versa.
You can use the Content component to handle scrolling in code.
You can use scrollToTop() or scrollToBottom() as well as scrollToPoint(), whatever fits your need.
For more info see https://ionicframework.com/docs/api/content#scrollToTop
import { Component, ViewChild } from '#angular/core';
import { Content } from 'ionic-angular';
#Component({...})
export class MyPage{
#ViewChild(Content) content: Content;
scrollToTop() {
this.content.scrollToTop();
}
}
check the ionic docs for info on component methods https://ionicframework.com/docs/api/content
.html
<ion-content>
<ion-icon name="arrow-dropdown" (click)="scrollToBottom()"></ion-icon>
//..... your content ......
<ion-icon name="arrow-dropup" (click)="scrollToTop()"></ion-icon>
</ion-content>
.ts
import { Component, ViewChild } from '#angular/core';
import {IonContent} from '#ionic/angular';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
#ViewChild(IonContent) theContent: IonContent;
scrollToBottom(){
this.theContent.scrollToBottom();
}
scrollToTop(){
this.theContent.scrollToTop();
}
}

How to include the user credentials in every sidebar of very pages in ionic

I want to have an sidebar that can display the name of the user who logged in. I have an account page that display all the details of the user. This is the code of the typescript below for the accounts page.
import { Component } from '#angular/core';
import { NavController, AlertController} from 'ionic-angular';
import {Headers} from "#angular/http";
import 'rxjs/add/operator/map';
import {Storage} from "#ionic/storage";
import { Global } from '../../providers/global';
#Component({
selector: 'page-account',
templateUrl: 'account.html',
})
export class AccountPage {
constructor(public navCtrl: NavController,
private storage: Storage,
public alertCtrl: AlertController,
public global: Global
)
{
//
}
public ACCOUNT_URL = this.global.url + "/api/inspectors";
credentials:any;
contentHeader = new Headers({"Content-Type": "application/json"});
error: any;
user: any;
token_type: any;
access_token: any;
refresh_token:any;
ionViewDidLoad() {
console.log('ionViewDidLoad AccountPage');
this.getAccessToken();
this.getAccount();
}
getAccessToken(){
this.storage.get('access_token').then((value) => {
this.access_token=value;
});
}
getAccount(){
this.storage.get('user').then((value) => {
this.user=value;
});
}
}
and this is the code in my html.
<ion-header>
<ion-navbar color="danger">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Account</ion-title>
</ion-navbar>
</ion-header>
<ion-content class="page-account">
<ion-card>
<ion-item *ngIf="user">
<ion-card-content text-wrap>
<h2>Name: {{user.name}}</h2>
<p>{{user.cellphone_no}}</p>
<p> Address: {{user.address}} </p>
<p> Email: {{user.email}} </p>
</ion-card-content>
</ion-item>
</ion-card>
</ion-content>
What I want to happen is to delete the account pages and put the details of the user in top of the sidebar. So I have to put it into the app.html or app.ts but how can I define the property in my root component in order to display the details of that user.
Here is the code below in my app.component.ts
import { Component, ViewChild} from '#angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import {Storage} from "#ionic/storage";
import { LoginPage } from '../pages/login/login';
import { AccountPage } from '../pages/account/account';
import { InspectionPage } from '../pages/inspection/inspection';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = LoginPage;
#ViewChild(Nav) nav: Nav;
pages: Array<{title: string, component: any, icon: string, color: string}>;
constructor(platform: Platform,
statusBar: StatusBar,
private storage: Storage,
splashScreen: SplashScreen) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
});
// used for an example of ngFor and navigation
this.pages = [
//{ title: 'Home', component: HomePage, icon: 'home', color: 'primary' },
{ title: 'Home', component: InspectionPage, icon: 'home', color: 'danger' },
{ title: 'Account', component: AccountPage, icon: 'person', color: 'primary' }
];
}
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.setRoot(page.component);
}
logout() {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.storage.remove('access_token');
this.storage.remove('username');
this.storage.remove('data');
this.storage.remove('user');
this.nav.setRoot(LoginPage);
}
}
and here is the code in my sidemenu or html.
<ion-menu [content]="content" id="myMenu">
<ion-header>
<ion-toolbar color="danger">
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button menuClose ion-item *ngFor="let p of pages" (click)="openPage(p)">
<ion-icon [name]="p.icon" [color]="p.color" item-left></ion-icon> {{p.title}}
</button>
<button menuClose ion-item (click)="logout()">
<ion-icon name="log-out" color="default" item-left></ion-icon> Logout
</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 swipeBackEnabled="false"></ion-nav>
What I want to happen is to put the details of the user in the sidebar like what I did in the account page. Sorry for my long question. I tried searching for it but can't find any answer to it.
Looking for help.
Thanks in advance.
I would recommend that you create a service to handle the state of the user login. That way the state is handled in a central place and it will be much easier to maintain.
One possible approach would be to use a BehaviourSubject inside your service, which you can then subscribe to on every page that you need your user object (like your account page and your app component).
import {Injectable} from '#angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class UserService {
// Observable user object (replace any with your user class/interface)
private _userObject = new BehaviorSubject<any>({});
// Expose an observable that can be used by components
userObject$ = this._userObject.asObservable();
// Method to update the user
changeUser(user) {
this._userObject.next(user);
}
}
You can now use the service like that (you have to implement the subscription logic in every component where you want to have access to your user):
import {Component} from '#angular/core';
import {UserService} from './user.service';
#Component({
selector: 'account-page'
})
export class AccountPage {
user: any;
subscription: Subscription;
constructor(private _userService: UserService) {}
ngOnInit() {
this.subscription = this._userService.userObject$
.subscribe(item => this.user = item);
}
ngOnDestroy() {
// prevent memory leak when component is destroyed
this.subscription.unsubscribe();
}
login() {
this._userService.changeUser({
name: 'Name' // Replace with name / user object
});
}
logout() {
this._userService.changeUser({});
}
}
As mentioned above, the big advantage is maintainability. If you ever change your user object, it only requires minimal changes, whereas the solution by #Tomislav Stankovic requires changes in every component where the user is used.
In your login page, when user is successfully logged-in, store data to localStorage
login(username,password){
this._api.userLogin().subscribe(res => {
if(res.status == 'ok'){
localStorage.setItem('user_first_name', res.user_first_name);
localStorage.setItem('user_last_name', res.user_last_name);
}
}
And then in app.component.ts get data from localStorage
this.first_name = localStorage.getItem('user_first_name');
this.last_name = localStorage.getItem('user_last_name');
Display data in app.html
<p>{{first_name}}</p>
<p>{{last_name}}</p>
On log-out clear localStorage
logout(){
localStorage.clear();
}

Ionic 2 Side Menu Not Popping Up

I am completely new to Ionic as of last night and I've created a blank project and now stupidly realized that I'd like to have a side menu in there. So I've followed a couple of online tutorials to add one in, but no matter what I try I can get the menu to show when I click the menu toggle icon button.
Here's what I've added in to try and make this work:
app.html
<ion-menu side="right" [content]="content">
<ion-content>
<ion-list>
<button>Page 1</button>
<button>Page 2</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav #content [root]="rootPage" swipeBackEnabled="false"></ion-nav>
app.component.ts:
import { Component, ViewChild } from '#angular/core';
import { Platform, Nav } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HomePage } from '../pages/home/home';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = HomePage;
#ViewChild(Nav) nav: Nav;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
});
}
}
home-logged-in.html:
<ion-header>
<ion-navbar color='primary'>
<button ion-button menu-toggle>
<ion-icon name="menu"></ion-icon>
</button>
</ion-navbar>
</ion-header>
<ion-content padding>
</ion-content>
Wrong attribute. Replace:
<button ion-button menu-toggle>
With:
<button ion-button menuToggle>