How to Use Ionic 2 Navbar API - ionic2

I am using documentation
http://ionicframework.com/docs/v2/api/components/navbar/Navbar/
while using this api, i have injected dependency Navbar to my page.I can enable/disable backbutton with API. I wish to capture click on this button and nagivate using backButtonClick(). Can you tell me how to use this method?

You can use Angular's #ViewChild. First, you inject the child component into the one we need to do an interaction:
import { ViewChild } from '#angular/core';
import { Navbar } from 'ionic-angular';
export class MyNavBar {
#ViewChild(Navbar) navbar: Navbar;
}
Then, you can call your backButtonClick method:
this.navbar.backButtonClick = (e: UIEvent) => {
// Print this event to the console
console.log(e);
// Navigate to another page
this.navCtrl.push(AnotherPage);
}

Related

How to disable keyboard hide on touching outside of textfield in iOS app using ionic 2/3

I want to disable keyboard hide when touching outside of textfield in iOS application which is build by using ionic. I want to hide keyboard by using only keyboard return button. Is there any way to disable keyboard hide on touching outside textfield?
Make sure you have
<preference name="KeyboardDisplayRequiresUserAction" value="false"/>
in your config.xml if you want to call focus() on iOS.
Then create directive:
import { Directive, ElementRef, Renderer } from '#angular/core';
#Directive({
selector: '[autofocuser]'
})
export class Autofocuser {
constructor(private element: ElementRef, private renderer: Renderer) {}
ngAfterViewInit() {
let el = this.element.nativeElement.children[0]
el.addEventListener('blur', (event) => {
this.stopBubble(event);
this.renderer.invokeElementMethod(el, 'focus', []);
});
}
stopBubble(event) {
event.preventDefault();
event.stopPropagation(); //Stops event bubbling
}
}
Mark your input field with the directive.
See https://github.com/ionic-team/ionic-plugin-keyboard/issues/81.
check this Doc.
Install this below plugin
ionic cordova plugin add ionic-plugin-keyboard
npm install --save #ionic-native/keyboard
inside your html page.
<ion-input type="text" (blur)="closeKeyboard()"></ion-input>
inside your ts file
import { Keyboard } from '#ionic-native/keyboard';
constructor(private keyboard: Keyboard) { }
closeKeyboard(){
this.keyboard.close();
(or)
this.keyboard.open();
}
it will close the keyboard when you touch outside the keyboard
Update try using this in your input
(mousedown)="something(); $event.preventDefault()"

Ionic 2 - Add a component dynamically to app root

I'm trying to add a custom component dynamically (from a directive) into my Ionic 2 app root...
I've tried many things, but nothing works!
I know that I could add a container with an id to hold my custom component and reach it through an Input in my directive, but I don't want to use that solution.
I need to be able to add any custom component into app root.
This is my last attempt:
import { Directive, ElementRef,
ComponentFactoryResolver,
ViewContainerRef,
ApplicationRef
} from '#angular/core';
import { App, ViewController } from 'ionic-angular';
import { MyComponent } from '../../components/myComponent/myComponent';
#Directive({
selector: '[myDirective]',
host: {
'(click)': 'onClick()',
}
})
export class MyDirective {
myComponent: any;
constructor( private el: ElementRef,
private app: App,
private appRef: ApplicationRef,
private vcr: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) {
this.myComponent = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
}
onClick() {
this.app._appRoot._overlayPortal._viewport.createComponent(this.myComponent);
}
}
It should create my component as a sibling of _overlay elementin app root, but I only receive an error message:
No provider for ViewController
What am I doing wrong? Any suggestion or any other solution?

How to test required props in React

I'm trying to write simple test with React and Jest.
Component:
import React from "react";
class Task extends React.Component {
render() {
let onDelete = this.props.onDelete;
return (
<li>
<div className="collapsible-header"><i className="material-icons" onClick={() => onDelete(this.props.taskId)}>delete</i>{this.props.title}</div>
<div className="collapsible-body"><p>{this.props.description}</p></div>
</li>
);
}
};
Task.propTypes = {
title: React.PropTypes.string.isRequired,
taskId: React.PropTypes.number.isRequired,
onDelete: React.PropTypes.func.isRequired,
description: React.PropTypes.string
};
Task.defaultProps = {
description: ''
};
export default Task;
Test
import React from 'react';
import Task from '../src/components/Task';
import renderer from 'react-test-renderer';
test('Task should require properties', () => {
const component = renderer.create( //this will give me React warnings which I would like to assert
<Task></Task>
);
});
Now I would like to assert that title, taskId and onDelete is required for Task component. That I will get React warning about not specifying them (or passing different types).
You can use a spy to find out if any kind of exception was thrown from react. Many people use a library called Sinon.js. From the documentation "A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls".
There is a great solution described in more detail here:
How to test React PropTypes through Jest?

How to select tabs in ionic 2?

I'm struggling to create a basic application in Ionic2 that uses both the side-menu and the tabs navigation. I understand the concepts of the navigation stack and that each tab has its own navigation stack, but I can't grasp the control over the tabs themselves.
The tabs starter template initializes a project with one ion-nav having its rootpage pointing to "rootPage", a property of the #App pointing to a TabsPage class.
<ion-nav id="nav" [root]="rootPage" #content></ion-nav>
The TabsPage class defines 3 properties, one for each page, pointing to their respective classes (each class decorated with #Page). But the TabsPage class itself doesn't seem to have any function, or be injected with a tabs controller and I find little to no documentation on how to acquire a Tabs instance (there are instance methods referenced on http://ionicframework.com/docs/v2/api/components/tabs/Tabs/)
What I managed to do:
Use one tab to control the other.
import {Page, Tabs} from 'ionic-angular';
#Page({
templateUrl: 'build/pages/timeline/timeline.html'
})
export class Timeline {
tabs:Tabs;
constructor(tabs:Tabs) {
this.tabs=tabs;
this.selectTab(2);
}
selectTab(i:number) {
this.tabs.select(i);
}
}
The page above is injected with a Tabs instance, which inherits from NavController. The Tabs instance has the desired select method, and I can point to a different tab (by index, not by name). So in this situation selecting my 'timeline' tab will trigger the constructor, and instead of going to the timeline tab we end up selecting the 2nd tab.
What I would like to do: navigate to a tab with a link in the side-menu.
My side-menu consists of two ion-items, simple buttons with a click listener. In Ionic 1.x I could use a ui-sref or a href to match a certain state, but in Ionic 2 I can't figure out how to control my tabs.
I can access the ion-nav by giving it an id and using app.getComponent('nav'), but I can not target the ion-tabs this way (hoping it would be bound to a Tabs controller instance).
Each ion-tab is a declarative component for a NavController. Basically, each tab is a NavController. For more information on using navigation controllers take a look at the NavController API Docs.
So to access the array of tabs from inside a specific tab page (component) we can set our target path with as simple as :
NavController.parent
Now suppose, we are in a child page of one of our tabs - the component class will be somewhat similar as below:
import { Component } from '#angular/core';
import { NavController, Nav , Tabs } from 'ionic-angular';
// import Tabs
import { Page2} from '../page-2/page-2';
import { Page3} from '../page-3/page-3';
#Component({
templateUrl: 'build/pages/page-1/page1.html'
})
export class Page1 {
tab:Tabs;
// create a class variable to store the reference of the tabs
constructor(public navCtrl: NavController, private nav: Nav) {
this.tab = this.navCtrl.parent;
/*Since Tabs are declarative component of the NavController
- it is accessible from within a child component.
this.tab - actually stores an array of all the tabs defined
in the tab.html / tab component.
*/
}
goToTab2 (){
this.tab.select(1);
// the above line is self explanatory. We are just calling the select() method of the tab
}
goToTab3 (){
this.tab.select(2);
}
}
Hope this helps.
I get this working by following:
app.ts
import {App, IonicApp, Platform} from 'ionic-angular';
#App({
template: '<ion-nav id="nav" [root]="rootPage"></ion-nav>',
})
export class TestApp {
rootPage: any = TabsPage;
constructor(
private platform: Platform,
private app: IonicApp
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
});
}
}
tabs.html
<ion-menu [content]="content">
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<ion-item (click)="openPage(p)" *ngFor="#p of pages;>
<span>{{p.title}}</span>
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<ion-tabs id="navTabs" #content swipe-back-enabled="false">
<ion-tab [root]="tab1"></ion-tab>
<ion-tab [root]="tab2"></ion-tab>
<ion-tab [root]="tab3"></ion-tab>
</ion-tabs>
tabs.ts
import {Page, NavController, MenuController} from 'ionic-angular';
#Page({
templateUrl: 'build/pages/tabs/tabs.html'
})
export class TabsPage {
pages: Array<{ title: string, component: any }>;
tab1: any = Tab1;
tab2: any = Tab2;
tab3: any = Tab3;
page: any = Page;
constructor(private nav: NavController,
private menu: MenuController) {
this.tab1 = Tab1;
this.tab2 = Tab2;
this.tab3 = Tab3;
this.pages = [
{ title: 'page-menu', component: Page }
];
}
openPage(page) {
// close the menu when clicking a link from the menu
this.menu.close();
// navigate to the new page if it is not the current page
}
}
my solution:
tabs.html : The main tip here is use #tabs
<ion-tabs tabs-only tabsLayout="icon-start" color="light" #tabs>
<ion-tab [root]="tabPage1" tabTitle="Mapa" tabIcon="qi-location arrow">
</ion-tab>
<ion-tab [root]="tabPage2" tabTitle="Em Andamento" tabIcon="qi-th-list" tabBadgeStyle="danger"> </ion-tab>
</ion-tabs>
tabs.ts: Use #ViewChild to bind the wild card used in tabs.html
#Component({
selector: 'page-tabs',
templateUrl: 'tabs.html',
})
export class TabsPage {
#ViewChild('tabs') tabRef: Tabs;
tabPage1: any = HomePage;
tabPage2: any = InProgressPage;
constructor() {
}
switchToHomePage(){
this.tabRef.select(0);
}
switchToInProgressPage(){
this.tabRef.select(1);
}
}
Another page to redirectc : Use #Inject(forwardRef(() => TabsPage)) to get access to parent page methods.
export class AnotherPage {
constructor(#Inject(forwardRef(() => TabsPage)) private tabsPage:TabsPage){}
switchToHome(){
this.tabsPage.switchToHomePage();
}
}

How to test for a `click` event on the icon button of the `material-ui` AppBar?

I'm testing the following React component:
import React from 'react'
import AppBar from 'material-ui/lib/app-bar'
class NavBar extends React.Component {
render () {
return (
<div>
<AppBar
title='My NavBar Title'
/>
</div>
)
}
}
export default NavBar
It's composed of a material-ui AppBar component. Using Tape and Enzyme, I want to simulate a click on the AppBar's IconButton:
import NavBar from './NavBar'
import React from 'react'
import test from 'tape'
import { /* I don't know if it's `shallow` or `mount` */ } from 'enzyme'
test('NavBar component test', (assert) => {
test('simulating a click on the icon button', (assert) =>
// How do I do this?
// The following results in error:
// const wrapper = shallow(<NavBar />)
// wrapper.find('AppBar').find('IconButton').simulate('click')
assert.end()
})
assert.end()
})
How can I do it properly?
Obs: I'm searching for IconButton because, according to the React Dev Tools tab, that's the name of the rendered icon button component.
You should use mount for testing components below the top level of the component.
I found a way to test whether the function is called, not using the .simulate('event'), just invoke the method directly.
const wrapper = shallow(<NavBar />)
//use sinon.spy( object, method) to spy the method, instead of sinon.spy(func)
const spy = Sinon.spy(wrapper.renderer._instance._instance, 'click')
//inovke
wrapper.renderer._instance._instance.click()
expect(spy.called).to.be.true
You could find the method inside the .renderer._instance or its children _instance objects (depending on how deep the element is) and then use sinon.spy to spy this method.
I don't like this way, but this is the only way I know how to spy a method till now.