Ionic2 dynamic navigation - dynamic

I'm building an app where the data comes from the server. The menu is dynamic, and the server can send different menus depending on the user profile. I will never know what will be the component/page, that the menu item will have, I just need to have that component/page available.
The main problem is that I need to do a lot of components/pages imports and I do not want to that in every component/page.
I created a service, where all the imports are made and a method exists to return the correct component, so the navController could navigate.
import { Injectable } from '#angular/core';
//Import navigation pages
import { NotificationsPage } from "./../pages/notifications/notifications";
import { ClubPage } from "./../pages/club/club";
import { ActivitiesPage } from "./../pages/activities/activities";
import { NewsPage } from "./../pages/news/news";
import { CalendarPage } from "./../pages/calendar/calendar";
import { NewsletterPage } from "./../pages/newsletter/newsletter";
import { SettingsPage } from "./../pages/settings/settings";
import { FavoritesPage } from "./../pages/favorites/favorites";
import { SubmenuPage } from "./../pages/submenu/submenu";
import { ContentDetailsPage } from "./../pages/contentdetails/contentdetails";
#Injectable()
export class ViewNavigatorService
{
public NOTIFICATIONS:string = "notifications";
public CLUB:string = "club";
public ACTIVITIES:string = "activities";
public NEWS:string = "news";
public CALENDAR:string = "calendar";
public NEWSLETTER:string = "newsletter";
public SETTINGS:string = "settings";
public FAVORITS:string = "favorits";
public SUBMENU:string = "submenu";
public CONTENT_DETAILS:string = "content-details";
public GetComponent(page:string, data?:any):any
{
let Component = null;
switch (page)
{
case this.NOTIFICATIONS: Component = NotificationsPage; break;
case this.CLUB: Component = ClubPage; break;
case this.ACTIVITIES: Component = ActivitiesPage; break;
case this.NEWS: Component = NewsPage; break;
case this.CALENDAR: Component = CalendarPage; break;
case this.NEWSLETTER: Component = NewsletterPage; break;
case this.SETTINGS: Component = SettingsPage; break;
case this.FAVORITS: Component = FavoritesPage; break;
case this.SUBMENU: Component = SubmenuPage; break;
case this.CONTENT_DETAILS: Component = ContentDetailsPage; break;
default: Component = null; break;
}
return Component;
}
}
If I only inject the service in a parent page it works, but if I also inject the service in a child page, I get this error:
Can't resolve all parameters for SubmenuPage: (NavController, NavParams, PopoverController, AlertController, ModalController, ?).
The ? should be the "ViewNavigatorService".
Why this error happens?
Is there a better way to do this? What are you using when your app uses dynamic navigation?

Related

How to get the Base URL including the context for the storefront?

How to get the Base URL including the context for the storefront?
For example, for this URL
https://spartacus.c39j2-walkersde1-d4-public.model-t.cc.commerce.ondemand.com/electronics-spa/en/USD/OpenCatalogue/Cameras/Digital-Cameras/Digital-SLR/c/578
How do I get just
https://spartacus.c39j2-walkersde1-d4-public.model-t.cc.commerce.ondemand.com/electronics-spa/en/USD/
You can get separately the origin (https://s(...).com) and the context URL parameters (electronics-spa/en/USD/).
The origin
import { DOCUMENT } from '#angular/common';
// ...
constructor(#Inject(DOCUMENT) private document: any){}
//...
const origin = this.document.location.origin;
// "https://s(...).com"
Note: it won't work in Server Side Rendering! Please use Spartacus' injection token SERVER_REQUEST_ORIGIN then:
import { DOCUMENT } from '#angular/common';
import { PLATFORM_ID } from '#angular/core';
import { SERVER_REQUEST_OTIGIN } from '#spartacus/core';
// ...
constructor(
#Inject(DOCUMENT) private document: any,
#Inject(PLATFORM_ID) private platformId,
#Inject(SERVER_REQUEST_ORIGIN) private serverRequestOrigin
){}
// ...
let origin;
if (isPlatformServer(this.platformId)){
origin = this.serverRequestOrigin;
} else {
origin = this.document.location.origin;
}
The context URL parameters
import { Router } from '#angular/router';
// ...
constructor(private router: Router){}
// ...
const context = router.serializeUrl(router.createUrlTree(''));
// "electronics-spa/en/USD/"
Final result
const result = `${origin}/${context}`;
// "https://s(...).com/electronics-spa/en/USD/"

Having Problem with React-native-gesture-handler(cannot find symbol String overflow = ((ReactViewGroup) view).getOverflow();)

I am having an issue with react-native-gesture-handler. Whenever I link my react-native-gesture-handler to my project it stops working and shows this error. But after unlinking react-native-gesture-handler from my project the application work fine. But as I need to navigate from several screens, I need gesture handler.
First I thought it was the problem of the react-native version as I was using react-native version 0.57.0 but it's not working on 0.58.0 and 0.55.4 either.
package com.swmansion.gesturehandler.react;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.views.view.ReactViewGroup;
import com.swmansion.gesturehandler.PointerEventsConfig;
import com.swmansion.gesturehandler.ViewConfigurationHelper;
public class RNViewConfigurationHelper implements ViewConfigurationHelper {
#Override
public PointerEventsConfig getPointerEventsConfigForView(View view) {
PointerEvents pointerEvents;
pointerEvents = view instanceof ReactPointerEventsView ?
((ReactPointerEventsView) view).getPointerEvents() :
PointerEvents.AUTO;
// Views that are disabled should never be the target of pointer events. However, their children
// can be because some views (SwipeRefreshLayout) use enabled but still have children that can
// be valid targets.
if (!view.isEnabled()) {
if (pointerEvents == PointerEvents.AUTO) {
return PointerEventsConfig.BOX_NONE;
} else if (pointerEvents == PointerEvents.BOX_ONLY) {
return PointerEventsConfig.NONE;
}
}
switch (pointerEvents) {
case BOX_ONLY: return PointerEventsConfig.BOX_ONLY;
case BOX_NONE: return PointerEventsConfig.BOX_NONE;
case NONE: return PointerEventsConfig.NONE;
}
return PointerEventsConfig.AUTO;
}
#Override
public View getChildInDrawingOrderAtIndex(ViewGroup parent, int index) {
if (parent instanceof ReactViewGroup) {
return parent.getChildAt(((ReactViewGroup) parent).getZIndexMappedChildIndex(index));
}
return parent.getChildAt(index);
}
#Override
public boolean isViewClippingChildren(ViewGroup view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && !view.getClipChildren()) {
if (view instanceof ReactViewGroup) {
String overflow = ((ReactViewGroup) view).getOverflow();
return "hidden".equals(overflow);
}
return false;
}
return true;
}
}
You can try manual linking.
Also check this issue out :
https://github.com/kmagiera/react-native-gesture-handler/issues/205
If you get the problem in Android, but not iOS, it could be that you need to add a polyfill for symbols. I can't remember where I found this, but I have used it in my own projects and it works. Just stick it in your index.js:
if (Platform.OS === 'android') {
if (typeof Symbol === 'undefined') {
if (Array.prototype['##iterator'] === undefined) {
Array.prototype['##iterator'] = function() {
let i = 0;
return {
next: () => ({
done: i >= this.length,
value: this[i++]
})
};
};
}
}
}

Aurelia `#dynamicOptions` mixed with `#bindable`s

I am developing using aureliajs. By now I am working on a custom attribute which has marked to have dynamic options. For example consider following code:
import {dynamicOptions, inject} from 'aurelia-framework';
#dynamicOptions
#inject(Element)
export class SquareCustomAttribute {
constructor(element){
this.element = element;
}
propertyChanged(name, newValue, oldValue){
switch(name){
case 'fill':
this.element.style.backgroundColor = newValue;
break;
case 'size':
this.element.style.width = this.element.style.height = `${newValue}px`;
break;
default:
this.element.style[name] = newValue;
break;
}
}
}
now for example consider that I want to give the property fill, defaultBindingMode of twoWay, so I will try to add the #bindable property in class. So the code will change to this:
import {dynamicOptions, inject} from 'aurelia-framework';
#dynamicOptions
#inject(Element)
export class SquareCustomAttribute {
#bindable fill;
constructor(element){
this.element = element;
}
propertyChanged(name, newValue, oldValue){
switch(name){
case 'fill':
this.element.style.backgroundColor = newValue;
break;
case 'size':
this.element.style.width = this.element.style.height = `${newValue}px`;
break;
default:
this.element.style[name] = newValue;
break;
}
}
}
And binding stops working.
So, the first question is how to set defaultBindingMode for dynamicOptions?
And another little question. As aurelia.io says, Binding to a dynamic options attribute works exactly the same as binding to an options attribute in the DOM.. According to this sentence, I expect to bind dynamic options dash seperated and retrieve the in camel case on optionsChanged method. But dash seperated options bound from view, receives dash separated and camels, camels. Is this correct according to referenced sentence from aurelia.io?
Thanks to #bigopon, this issue is being followed up in this issue and I think any additional comment on that will be beneficial before making changes on aurelia-framework.

Aurelia CLI - au run --watch misses obvious type errors

Using AureliaCLI and TypeScript.
I have a service which returns a specific type and a component which incorrectly assigns the returned object to a variable of another type:
import { ItemService } from "./itemService";
import { Item } from '../server/backend';
export class ItemDetails {
item: Item = null;
constructor(private itemService: ItemService) {
}
activate() {
this.item = this.itemService.getItem();
}
}
and
import { Seat } from "../server/backend";
export class ItemService {
item: Seat;
constructor() {
this.item = null;
}
getItem(){
return this.item;
}
setItem(item: Seat){
this.item = item;
}
}
This will generate an error when 'au run --watch' is run the first time, but any subsequent change to either file does not produce an error.
Can I configure AureliaCLI to look at dependant files also?
Thanks
Right, as you can probably guess, I am new to TypeScript.
I forgot to add a return type to the service method...
This will cause the error to be triggered:
getItem(): Seat {
return this.item;
}

React Native Android Native UI Component the #ReactProps doesn't execute

I have build a map Native UI Component at the Android platform. When the view is imported in the view as this
<AMapView style={styles.mapContainer} mode={2} onRegionChange={this._onReginChange.bind(this)}/>
The onRegionChange event is executed but the property method doesn't execute. enter link description here
class AMapCustomView extends Component {
constructor(props) {
super(props)
this._onRegionChange = this._onRegionChange.bind(this)
}
_onRegionChange(event: Event) {
if (!this.props.onRegionChange) {
return
}
this.props.onRegionChange(event.nativeEvent)
}
render() {
return <RCTAMap {...this.props} onRegionChange={this._onRegionChange}/>
}
}
AMapCustomView.propTypes = {
...View.propTypes,
mode: PropTypes.number,
onRegionChange: PropTypes.func
}
var RCTAMap = requireNativeComponent('RCTAMap', AMapCustomView)
module.exports = AMapCustomView;
Java Code:
#Override
public Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
AMapLocationEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRegionChange")
);
}
#ReactProp(name="mode", defaultInt = 1)
public void setMode(AMapView mapView, int type) {
Log.d(TAG, "mode:" + type);
}
Make sure you import com.facebook.react.uimanager.annotations.ReactProp;, I think the path used to change and the old ReactProp will no more work in more recent React Native version.