"ion-button + icon-only" inside component not working - ionic-framework

I'm using Ionic 3.*, tring to create a component that contains just a button.
The component code is:
#Component({
selector: 'profile-button',
templateUrl: 'profile-button.html',
})
export class ProfileButtonComponent {
constructor(
private popoverCtrl: PopoverController
) {}
/**
* Present the Profile popover
* #param ev
* #returns {Promise<any>}
*/
async presentPopover(ev) {
let popover = this.popoverCtrl.create(ProfilePopover);
return popover.present({
ev
});
}
}
and my template is:
<button ion-button icon-only (click)="presentPopover($event)" title="Profile">
<ion-icon name="person"></ion-icon>
</button>
The problem:
The problem is that the icon-only directive is just ignored. The button still have a background color.
If I put the template outside the component, it shows the right style.
Looks like the directives is not available inside a Component. My component is inside a custom module, not on AppModule.
How can I solve this? Found that on Ionic2 i need to import the directives manually, but it don't work on Ionic3.

I've solved the issue, maybe with an workarround:
Changed the component selector to attribute selector: [profile-button]
Wrapped the template in a <ion-buttons end> tag
Called the component as an attribute of <ion-buttons end>
<ion-buttons profile-button end></ion-buttons>
Note: The issue wasn't with icon-only directive. But it's a style issue on Ionic that required the button directly child of the toolbar or ion-buttons to get proper styles.

I found solution on another S.O. thread.
In your *.module.ts add IonicModule into imports section.
#NgModule({
imports: [
CommonModule, // <-- standard Angular module
IonicModule // <-- standard ionic module
], ...
})

In your template try adding your content inside a ion-content
<ion-content>
</ion-content>

you can remove ion-button and add:
class="disable-hover button button-ios button-clear button-clear-ios button-clear-ios-dark"
change dark as you want.

Related

Show/Hide password button not working when input is active in Ionic 3

I am trying to implement the show/hide button for the password field in Ionic 3. I have got the code help from here
login.html
<ion-item>
<ion-input [type]="passwordType" placeholder="Password" formControlName="password"></ion-input>
<ion-icon item-end [name]="passwordIcon" class="passwordIcon" (click)='hideShowPassword()'></ion-icon>
</ion-item>
login.scss
.passwordIcon{
font-size: 1.3em;
position: absolute;
right: .1em;
top: .5em;
z-index: 2;
}
login.ts
passwordType: string = 'password';
passwordIcon: string = 'eye-off';
hideShowPassword() {
this.passwordType = this.passwordType === 'text' ? 'password' : 'text';
this.passwordIcon = this.passwordIcon === 'eye-off' ? 'eye' : 'eye-off';
}
I have done one modification in the .scss file and made the icon absolute so that it appears on top of the input field instead of the side.
This icon click is working when the Input field is not active/selected but if I am in the middle of typing in the Input Field, the click is not working/recognized. Please help.
With the solution suggested my field looks like this.
I'm not entirely sure of what
... and made the icon absolute so that it appears on top of the input field instead of the side
would mean, but still, using position: absolute on top of inputs may lead to bugs specially on iOS.
Another possible issue of your code is that buttons are designed to handle issues related with taps in mobile devices, but icons may not work properly sometimes.
Anyway, please take a look at this working Stackblitz project to do something like this:
The code is quite simple actually - the idea is to use a button with an icon instead of just an icon to avoid issues with the tap event:
Component
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public showPassword: boolean = false;
constructor(public navCtrl: NavController) {}
public onPasswordToggle(): void {
this.showPassword = !this.showPassword;
}
}
Template
<ion-header>
<!-- ... -->
</ion-header>
<ion-content padding>
<!-- ... -->
<ion-item>
<ion-input placeholder="Password" [type]="showPassword ? 'text' : 'password'" clearOnEdit="false"></ion-input>
<button (click)="onPasswordToggle()" ion-button clear small item-end icon-only>
<ion-icon [name]="showPassword ? 'eye-off' : 'eye'"></ion-icon>
</button>
</ion-item>
</ion-content>
EDIT
Based on your comments, one way to keep the button inside of the border would be not to apply the border to the input, but to the ion-item.
Something like this for example:
ion-item {
border: 1px solid #ccc;
border-radius: 10px;
}
would result in:

Ionic 2: View does not update based on model change

I have a very simple page with a couple of controls.
My issue is that the page does not pickup changes to the model when the icon in upper right corner is clicked. This toggles the showFilterPane variable, which again should show or hide a div based on *ngIf="showFilterPane".
I have another page just like this one working, and I can not figure out why this isn't.
Any tips?
(I've tried using the ChangeDetectorRef.detectChanges(); which works, but then the rangeslider will not work. The draggable point doesn't update, or does not move to where you tap.)
The page:
<ion-header>
<ion-navbar>
<ion-title>MY AO</ion-title>
<ion-buttons end>
<button ion-button (click)="toggleFilterPane()" icon-only>
<ion-icon name="options"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div class="container">
<div class="left">
<div *ngIf="isSearching" class="spinner-container">
<ion-spinner></ion-spinner>
</div>
<!-- put content here -->
</div>
<div class="right" *ngIf="showFilterPane">
<ion-list inset>
<ion-list-header>BANA</ion-list-header>
<ion-item>
<ion-select multiple="true" [(ngModel)]="woTrackFilter">
<ion-option>1</ion-option>
<ion-option>2</ion-option>
<ion-option>3</ion-option>
<ion-option>4</ion-option>
<ion-option>5</ion-option>
</ion-select>
</ion-item>
</ion-list>
<ion-list inset>
<ion-list-header>TEKNIKSLAG</ion-list-header>
<ion-item>
<ion-select multiple="true" [(ngModel)]="woDisciplineFilter">
<ion-option>Signal</ion-option>
<ion-option>Bana</ion-option>
<ion-option>EL</ion-option>
<ion-option>Tele</ion-option>
</ion-select>
</ion-item>
</ion-list>
<ion-list inset>
<ion-list-header>DAGAR</ion-list-header>
<ion-item>
<ion-range min="10" max="80" step="4" [(ngModel)]="woDaysFilter">
<ion-label range-left>10</ion-label>
<ion-label range-right>80</ion-label>>
</ion-range>
</ion-item>
</ion-list>
<button ion-button (click)="doSearch()">Search</button>
</div>
</div>
</ion-content>
The component:
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { WorkOrderDashboardPage } from "../work-order-dashboard/work-order-dashboard";
#Component({
selector: 'page-work-order-list',
templateUrl: 'work-order-list.html'
})
export class WorkOrderListPage {
private isSearching: boolean = false;
private showFilterPane: boolean=false;
private woTrackFilter: string[];
private woDisciplineFilter: string[];
private woDaysFilter: number;
constructor(public navCtrl: NavController, public navParams: NavParams) {
// Initialize storage providers here
}
ionViewDidLoad() {
console.log('ionViewDidLoad WorkOrderListPage');
}
toggleFilterPane(): void {
this.showFilterPane = !this.showFilterPane;
}
viewWorkOrder(event, workOrder): void {
this.navCtrl.push(WorkOrderDashboardPage, { workOrder: workOrder });
}
doSearch(): void {
console.log(this.woTrackFilter);
console.log(this.woDisciplineFilter);
console.log(this.woDaysFilter);
}
}
UPDATE: Found workaround
I tried creating a separate app, where the exact same code is working. That lead me to think something wasn't right on the LoginPage, the page that called setRoot() to the above page.
The login code looked like this:
WLAuthorizationManager.login("UserLogin", data).then(() => {
// Success
console.log("Logged in");
this.navCtrl.setRoot(WorkOrderListPage);
},
(err) => {
// failed
console.error(err);
this.showError("Username or password is incorrect");
})
I then figured it might be some Zone issue, and wrapped the setRoot call in zone.run() like this:
WLAuthorizationManager.login("UserLogin", data).then(() => {
// Success
console.log("Logged in");
this.zone.run(() =>
this.navCtrl.setRoot(WorkOrderListPage)
);
},
(err) => {
// failed
console.error(err);
this.showError("Username or password is incorrect");
})
After that the view started to respond as expected. I feel this is a bit of a hack. Can someone shed some light as to what is happening here?
Seems like you are basically using ngZone to make sure Angular knows you changed things so it will reload that part of the DOM to reflect the changes. I don't feel like it's a hack, because you are just making sure that it works as intended.
Angular 2 has some optimization features that help make your app run smoother and one of those is avoiding DOM updates whenever and wherever possible. By using zones (or ngZones) you are basically telling Angular "pay attention to this part, it changes and I need that change to be reflected in the DOM".
I've run into that sort of problem before myself and using zones is usually your best bet. Got into situations where a part of the interface would be stuck unless you touched a button or somesuch.
Another workaround (at least for range sliders) is using the AppllicationRef tick() method, which forces a DOM update. More info about it here.

In Ionic 2, how do I create a custom component that uses Ionic components?

Creating a basic directive is simple:
import {Component} from 'angular2/core';
#Component({
selector: 'my-component',
template: '<div>Hello!</div>'
})
export class MyComponent {
constructor() {
}
}
This works as expected. However, if I want to use Ionic components in my directive things blow up.
#Component({
selector: 'nl-navbar',
template: `
<ion-header>
<ion-navbar color="primary">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title >
<span>Complaints</span>
</ion-title>
<ion-buttons *ngIf="!hideCreateButton" end>
<button ion-button class="navBtnRight" (click)="openPopover($event)">
<ion-icon name="md-more"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
`,
inputs: ['hideCreateButton']
})
export class CustomNavbar {
public hideCreateButton: string;
constructor(public popoverCtrl: PopoverController) {
}
createNew(): void {
// this.nav.setRoot(CreateNewPage, {}, { animate: true, direction: 'forward' });
}
openPopover(myEvent) {
let popover = this.popoverCtrl.create(PopoverPage);
popover.present({
ev: myEvent
});
}
}
using custom navbar like this:
<nl-navbar [hideCreateButton]="hidebutton()"></nl-navbar>
and my ts file looks like this:
private hideCreateButton: boolean = false;
public hidebutton(): boolean {
return this.hideCreateButton;
}
The directive is rendered, but Ionic components are not transformed, and so wont look/work properly. Sometimes it works in android device only.
I can't find any examples on this. How should I do this?
Make sure that the module that contains your custom component has: imports: [IonicModule]

Update view and value in ionic 2

Hi i just started using ionic 2 for my project , how to update ui value in ionic 2? jus simply when we click button some text changed. I tried this but didnt work
home.ts
#Component({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
public test: any;
constructor(private nav: NavController) {
}
update(){
this.test = "updated text";
}
}
home.html
<ion-content>
<p>{{test}}</p>
<button (click)="update()">update</button>
</ion-content>
Please help, thanks!
On HTML you should use {{test}} as you are modifying test varaible value.
<ion-content>
<p>{{test}}</p>
<button (click)="update()">update</button>
</ion-content>
The possibility is, you might have missed to bootstrap you application main component, you can see similar kind of answer here
change your home.html to this
<ion-content>
<p>[(ngModel)]="test"</p>
<button (click)="update()">update</button>

Ionic 2/ Angular 2 => Use ionic 2 html tags inside angular 2 component

I want to split a Ionic2 Page into smaller components. In addition I have created Angular2 Components which I insert in the Ionic2 Page. See Code.
If I now use Ionic2 HTML tags in the Angular2 Componentes I get the
No value accessor for '' "
error for my <ion-textarea> tag.
Ionic Page:
#Page({
selector: 'game',
directives: [QuestionComponent, AnswerComponent],
templateUrl: 'build/pages/quiz/quiz.page.html',
styles: [`
`],
)}
...
Ionic Page HTML:
<ion-navbar *navbar>
<ion-title>Game: {{game.id}} -> Round {{round}}</ion-title>
<!-- Question Card -->
<question></question>
<!-- Answer Card -->
<answer></answer>
Angular2 Component:
import {Component} from 'angular2/core'
import {Answer} from "../../../models/answer";
import {AnswerService} from "../../../services/answer.service";
#Component({
selector: 'answer',
providers: [AnswerService],
templateUrl: 'build/pages/quiz/answer/answer.page.html',
styles: [`
`],
})
...
Angular Component HTML:
<ion-card>
<ion-card-content>
<ion-item>
<ion-label floating>Answer</ion-label>
<ion-textarea [(ngModel)]="answerText">></ion-textarea>
<button outline item-right (click)="submitAnswer(answerText)">
Send
<ion-icon name="send"></ion-icon>
</button>
</ion-item>
</ion-card-content>
</ion-card>
Is it possible to use Ionic2 tag components in a Angular2 Component?
Or what is the best way to divided an Ionic 2 page into small components?
*EDIT
Solution
I have found a solution which solves my problem.
Link to solution => Using ion-input inside custom component
To solve it you have to insert the Ionic 2 Directive in the Angular2 Komponetne .
Fix Angular Component:
import {Component} from 'angular2/core'
import {IONIC_DIRECTIVES} from 'ionic-angular';
import {Answer} from "../../../models/answer";
import {AnswerService} from "../../../services/answer.service";
#Component({
selector: 'answer',
directives: [IONIC_DIRECTIVES],
providers: [AnswerService],
templateUrl: 'build/pages/quiz/answer/answer.page.html',
styles: [`
`],
})
I don't know Ionic but this works for Polymer elements and might work here as well - add ngDefaultControl:
<ion-textarea [(ngModel)]="answerText" ngDefaultControl></ion-textarea>
otherwise you'd probably need to implement a custom ControlValueAccessor like mentioned in https://github.com/angular/angular/issues/6639#issuecomment-174703547
See also ngModel: No value accessor for ''
Are you sure that the property answerText exists into the AnswerComponent class ?