Ionic 2: How to use custom build Cordova Plugin - ionic2

I'm already created cordova plugin and already used in Ionic 1, its worked. Then I tried to use it in Ionic 2 but I don't really know how to call that plugin. I follow the step from here to create my own plugin. And this is what i did:
plugin.xml
<name>myPlugin</name>
<js-module src="www/myPlugin.js" name="myPlugin">
<clobbers target="myPlugin" />
</js-module>
myPlugin.js
module.exports = {
myFunction: function (success, failure) {
cordova.exec(success, failure, "myPlugin", "myFunction", []);
}
};
hello-ionic.ts
import { Component } from '#angular/core';
declare var cordova: any;
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
constructor() {
}
click() {
if (typeof cordova !== 'undefined') {
cordova.plugins.myPlugin.myFunction();
}
}
}
But unfortunately it return me an error "Undefined myFunction" in hello-ionic.ts.

Here is what I did.
hello-ionic.ts
import { Component } from '#angular/core';
declare var myPlugin: any;
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
constructor() {
}
click() {
myPlugin.myFuntion(
(data) => {
console.log(data);
},
(err) => {
console.log(err);
});
}
}
declare var myPlugin: any; , myPlugin name I get from <clobbers target="myPlugin" />.
Note: Need to run the project in device only.

Following tutorial is a good resource to learn how to create custom cordova plugin :
https://taco.visualstudio.com/en-us/docs/createplugintutorial/
I have followed this tutorial to create multiple custom plugins and those are working fine in Ionic2.
One more thing to point out that the tutorial has not mentioned that:
You have to add your custom plugin in your ionic 2 project using following command:
ionic plugin add "folder path of your custom plugin"
Updated:
In your plugin.xml file, you have set "myPlugin" as target in clobbers tag.
So you should call your function as followed
window.myPlugin.myFunction();
Tip: Whenever you use custom plugin created by you(or someone else), inspect the application using Chrome Developer tools. In console tab of developer tools, you can inspect the window and other available objects and can find out correct way to call plugin's methods.

Related

Jest: Cannot read property of undefined when importing from own package nextjs

Got this weird bug when running the jest test, one of the UI component from a self defined UI package keeps throwing error, saying that an object in that package is undefined...
The component itself works perfectly fine, and the same component's testing logic works in another repo without nextjs, and that repo utilize #swc/jest for js transform in jest.config file.
I've also added that package itself to transformIgnorePatterns in jest-config file, but somehow the bug still presents...
The project itself is in nextjs, and below is a snapshot of the jest.config file
/** #type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
testPathIgnorePatterns: [
'<rootDir>/.next/',
'<rootDir>/node_modules/',
'<rootDir>/e2e/'
],
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['#testing-library/jest-dom/extend-expect'],
setupFiles: [require.resolve('whatwg-fetch')],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }]
},
transformIgnorePatterns: ['/node_modules/myPackage', 'jest-runner'],
testMatch: ['**/*.spec.{js,jsx,ts,tsx}'],
};
and the error itself goes Error: Uncaught [TypeError: Cannot read property 'object' of undefined], which tracks down to /node_modules/myPackage
how the package is used
import { InputBox } from 'myPackage';
const MyComponent = () => {
return (
<div>
<InputBox />
</div>
);
}
export default MyComponent;
and here's the test:
import { act, render } from '#testing-library/react';
import React from 'react';
describe('show component', () => {
it('should render', async () => {
await act(async () => {
render(
<MyComponent/>
);
});
});
});
I've found a similar question on stackoverflow Jest: Cannot read property of undefined when importing from own package
but that one is using regular js, and this one being next.js, there's really nowhere I can update .babelrc to update those configs...
Any input would be appreciated.
Update: it turns out the component that causes me bug is built on top of react-popper library, which is built on top of popper.js library. popper.js library doesn't support jsdom by default, and it requires to do jest mock. But my library is 2 layers abstractions on top of popper.js library, I'm not sure how to do that, or even if that is doable...

"__zone_symbol_currentTask":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","cancelFn":null,"runCount":0}}

I am getting this error
"__zone_symbol_currentTask":{"type":"microTask","state":"notScheduled","source":"Promise.then","zone":"angular","cancelFn":null,"runCount":0}}
while login facebook from my hybrid application. I have used
ng2-cordova-oauth
plugin to achieve facebook login. My code look like.
import { Component } from '#angular/core';
import {IonicPage, NavController, Platform} from 'ionic-angular';
import {OauthCordova} from '../../../node_modules/ng2-cordova-oauth/platform/cordova';
import {Facebook} from '../../../node_modules/ng2-cordova-oauth/core';
#IonicPage()
#Component({
selector: 'page-facebook',
templateUrl: 'facebook.html',
})
export class FacebookPage {
public oauth: OauthCordova;
private provider: Facebook;
public constructor(public navCtrl: NavController, private platform: Platform) {
this.oauth = new OauthCordova();
this.provider = new Facebook({
clientId: "1807864452579635",
appScope: ['id','story','picture','link','type','full_picture','message']
});
}
public login() {
this.platform.ready().then(() => {
this.oauth.logInVia(this.provider).then((success) => {
alert(JSON.stringify(success));
}, (error) => {
console.log(JSON.stringify(error));
});
});
}
}
I ran into this on a project I was working on too. The problem turned out to be that the ng2-cordova-oauth dependencies weren't installed. Specifically we had to run:
cordova plugin add cordova-plugin-inappbrowser
cordova plugin add cordova-plugin-whitelist
cordova prepare
You may also have to whitelist your site using the information found at https://github.com/apache/cordova-plugin-whitelist
Edit: You can't use ng2-cordova-oauth from the browser. You have to use a device or a simulator.
note that it is unlikely for anyone to see the original error in this code since it in part depends on external dependencies
You can use
JSON.stringify(error,Object.getOwnPropertyNames(e));
to get a clear description of the error you getting, because The __zone_symbol_currentTask is a property inserted into the Error object by Angular and JSON.stringify does not output the Error object's own properties (by default)
see also: Is it not possible to stringify an Error using JSON.stringify?

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?

Deeplink in Ionic 2 is not working

I am trying deeplinks with ionic 2 according to the procedure explained here, https://ionicframework.com/docs/v2/native/ionic-deeplinks/
First I added the plugin using,
ionic plugin add ionic-plugin-deeplinks --variable URL_SCHEME=http --variable DEEPLINK_HOST=cityknots.com
Then in my app.component.ts
export class MyApp {
rootPage = Wrapper;
constructor(platform:Platform) {
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();
Deeplinks.route({
'/test': UserHome
}).subscribe((match) => {
console.log('Successfully routed', match);
}, (nomatch) => {
console.warn('Unmatched Route', nomatch);
});
});
}
}
I try to hit the url (http://cityknots.com/test in the ios simulator's browser (safari) after i've built and run the app, but nothing is happening. I expect the app should be launched and navigate to UserHome component. There is nothing in the console too related to this.

Unit testing Angular 2 components inside a common library NPM Package no app context

I am kind of stumped on this. I have used the Angular 2 quick start projects as a reference for unit testing Angular 2 but it seems to assume you have an app in play. In my case we have NPM packages that have Angular 2 modules in them that are shared across various projects in our organization. I would like to be able to unit test the code inside these common libraries in isolation (without them being part of an app).
I am looking for examples or a tutorial or something explaining the best approach to this, Google has not provided any help.
Well I am doing in my Karma test something like:
Create a mock component
#Component({
template: "",
selector: 'mock'
})
export class MockComponent implements OnInit {
constructor() { }
ngOnInit() {
console.log("Is loaduing");
}
}
Create a mock service
class MockSomeService {
public subscribe(){}
public inizialize() {}
}
Create ROUTES array
export var ROUTES = [ {path:"/pathexample", component: MockComponent}]
Create DECLARATIONS array
export var DECLARATIONS:Component[] = [
MockComponent, ExampleComponent
];
Create PROVIDERS
const CONSTANTS_PROVIDERS: Provider[] = [
{ provide: SomeService, useClass: MockSomeService }
];
Write a test
describe('Component: example', () => {
beforeEach(() => {
TestBed.configureTestingModule({ declarations: DECLARATIONS, providers: CONSTANTS_PROVIDERS, imports: [RouterTestingModule.withRoutes(ROUTES)] });
});
it('should create an instance', inject([ExampleComponent], (component: ExampleComponent) => {
expect(component).toBeTruthy();
}));
});
If your component is using route.navigate you should use TestBed.overrideComponent and add template: '<router-outlet></router-outlet>' to your component if not have it yet and actually create the component like this TestBed.createComponent(ExampleComponent);