How to customize/style MapView in Expo on IOS and Android? - google-maps

I have generated a style on https://mapstyle.withgoogle.com, which gives me a JSON.
I followed the information here: https://github.com/airbnb/react-native-maps
For some reason, the styling does not work.

On IOS, by default, it is not google maps what opens. Solution: you need to add the following property to MapView: provider = { MapView.PROVIDER_GOOGLE }
On Android, it should work right away.
Here is a working example:
import React from "react";
import { StyleSheet, Text } from "react-native";
import { MapView, Constants } from 'expo';
export default class MapScreen extends React.Component {
render() {
return (
<MapView
style = { styles.container }
provider = { MapView.PROVIDER_GOOGLE }
customMapStyle = { generatedMapStyle }
/>
);}
}
const styles = StyleSheet.create({
container: {
flex: 1,
}
});
const generatedMapStyle = [...] // just paste the JSON here.

Also, make sure you have enabled the Maps SDK for iOS/Android services in your Google Cloud Platform, as well as including your API key in app.json. It took me 4 builds to find out....

Related

How do we actually register a customised formatter in react vega?

I have read the documentation so many times https://vega.github.io/vega-lite/docs/config.html#custom-format-type. I still don't understand how to implement this in react vega. What confuses me the most is this vega object.
view = new vega.View(...);
view.expressionFunction('customFormatA', function(datum, params) {
...
return "<formatted string>";
});
What I am currently doing in React:
import React from "react";
import ReactDOM from "react-dom";
import { createClassFromSpec } from "react-vega";
const spec = {}
const BarChart = createClassFromSpec({ mode: "vega-lite", spec: spec });
export default function TestPage2({ data }) {
return <BarChart data={{ table: data }} />;
}
Is there any example of implementing a custom format type that I can learn from?
There was an error in the documentation and a pull request has been submitted.
You should use vega instead of vega.View like so:
import { expressionFunction } from 'vega';
expressionFunction('customFormatA', function(datum, params) {
return datum;
});
However, note that custom formats do not work with binning; an issue has been opened for this.

How to load Loader on Every Route in Angular

Hello i want to put loader on every route link , when route link change show loader until all its component not load with api data.
Structure of Component
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
inside <router-outlet></router-outlet> i have other child component like and its data come from api.
<app-component1></app-component1>
<app-component2></app-component2>
so my problem is i cant put loader for page(route) wise if page load loader show and hide after all component load with dynamic(api) data
You can subscribe to RouterEvents to know when a route navigation is started to completed. You would also need a loader component in your AppComponent outside of your router-outlet and a flag to show/hide the loader. You can control loader visibility across the application using a LoaderService.
LoaderService
export class LoaderService {
isLoaderShown = new BehaviorSubject<boolean>(false);
constructor() { }
public showLoader() {
this.isLoaderShown.next(true);
}
public hideLoader() {
this.isLoaderShown.next(false);
}
}
You can use this LoaderService to show or hide the loader from anywhere in the application.
Update your AppComponent to add a new loader component. LoaderComponent just needs to contain a loader of your choice.
<app-header></app-header>
<app-loader *ngIf="showLoader"></app-loader>
<router-outlet></router-outlet>
<app-footer></app-footer>
Now we can control the loader display using the showLoader flag in AppComponent.
AppComponent
export class AppComponent implements OnInit {
showLoader = false;
constructor(
private loaderService: LoaderService,
private router: Router
) { }
ngOnInit() {
this.loaderService.isLoaderShown.subscribe(isLoaderShown => this.showLoader = isLoaderShown);
this.router.events.subscribe(routerEvent => {
if (routerEvent instanceof NavigationStart) {
this.loaderService.showLoader();
} else if (routerEvent instanceof NavigationEnd) {
this.loaderService.hideLoader();
} else if (routerEvent instanceof NavigationCancel) {
this.loaderService.hideLoader();
// Handle cancel
} else if (routerEvent instanceof NavigationError) {
this.loaderService.hideLoader();
// Handle error
}
});
}
}
Now, whenever a router navigation starts, we are showing the loader and hiding when navigation ends.
However, this doesn't take the API load times into consideration. For that, you could remove the this.loaderService.hideLoader(); from the NavigationEnd and add it in your API call subscription. This is the reason why we add it as a service. You can inject it onto your API Service and hide loader.
this.httpClient.get(url).subscribe(result => {
// Perform operations with the result
this.loaderService.hideLoader();
});
So, loader will be shown when navigation starts and when the API call result is available in service, loader can be hidden.

What is the right way to use hardware back button in Ionic 4?

i'm creating a ionic 4 app, and i want to use the device's hardware back-button to return at specific page
i'd checked in this page Handling hardware back button in Ionic3 Vs Ionic4 to create my code but it doesn't work
detallesusuario.page.ts
import { Subscription } from 'rxjs';
import { Component, OnInit, AfterViewInit, QueryList, ViewChildren}from '#angular/core';
import { Platform, IonRouterOutlet } from '#ionic/angular';
import { Router } from '#angular/router';
#Component({
selector: 'app-detallesusuario',
templateUrl: './detallesusuario.page.html',
styleUrls: ['./detallesusuario.page.scss'],
})
export class DetallesusuarioPage implements OnInit, AfterViewInit {
#ViewChildren(IonRouterOutlet) routerOutlets: QueryList<IonRouterOutlet> ;
sub:Subscription
constructor(private platform:Platform, private ruta:Router) { }
ngAfterViewInit(): void {
this.backButtonEvent();
}
ngOnInit() {
}
ngOnDestroy() {
this.sub.unsubscribe();
}
backButtonEvent() {
let u=0;
this.sub=this.platform.backButton.subscribeWithPriority(0, () => {
this.routerOutlets.forEach(async(outlet: IonRouterOutlet) => {
console.log('paso');
await this.ruta.navigate(['menu/inicio/tabs/tab1']);
});
});
}
}
When i deploy a app to a device, the button return to the previous page instead to go at the specific page
The hardware back button handling code is found in:
https://github.com/ionic-team/ionic/blob/master/core/src/utils/hardware-back-button.ts#L20
And that is exposed by the platform using platform.backButton:
https://github.com/ionic-team/ionic/blob/f44c17e03bfcd9f6f9375a19a8d06e9393124ac9/angular/src/providers/platform.ts#L21
https://github.com/ionic-team/ionic/blob/f44c17e03bfcd9f6f9375a19a8d06e9393124ac9/angular/src/providers/platform.ts#L48
It looks to me like you are using it correctly. I found this article showing the same technique, and also another forum post.
What looks strange to me is why you are getting IonRouterOutlet involved.
Have you tried it just using the router directly?
backButtonEvent() {
this.sub=this.platform.backButton.subscribeWithPriority(0, () => {
console.log('paso');
await this.ruta.navigate(['menu/inicio/tabs/tab1']);
});
}
Note: I'm assuming your choice of ngAfterViewInit make sense - I haven't double checked this.
However, you should also probably take a detailed look at this issue as it seems there are tons of problems with the hardware back button:
https://github.com/ionic-team/ionic/issues/16611

Get JSON Data in multiple components using reactjs and redux

I would like to show data from a single API to different components as I want to hit the API only once and distribute the data to multiple small components. I know I can do this by using redux state but not sure how to do it. Need your help to achieve this. Below is the code done so far.
homepage/index.js
import SlidingBanner from './banner/BannerList';
import Celebslider from './celebrityslider/CelebSlider';
class HomePage extends Component {
render() {
return (
<div>
<SlidingBanner />
<anotherslider />
</div>
);
}
}
export default HomePage;
BannerList.js
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { itemsFetchData } from '../../../actions/items';
class BannerList extends Component {
componentDidMount() {
this.props.fetchData();
}
render() {
let bannerArray = [];
let banner = this.props.items.banner
for (let key in banner) {
bannerArray.push(banner[key]);
return (
<div>
<Slider {...slidersettings}>
{this.props.items.banner.map((item) => (
<div key={item.id}>
<img src={item.image_url} className="img-responsive"/>
</div>
))}
</Slider>
</div>
);
}
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return (null);
}
}
BannerList.propTypes = {
fetchData: PropTypes.func.isRequired,
items: PropTypes.object.isRequired,
hasErrored: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired
};
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(BannerList);
anotherslider.js
Now in this file, i want to fetch another array of objects or object from the same API.
I tried to mount the API in container component but did not worked, I hope i am doing some mistake. Please correct.
If you want to fetch data in anotherslider.js file you must connect reducer to class/function inside it as well as you are making it in BannerList.js file.
Now before render call componentWillReceiveProps(nextProps) function and you will get your data here.
If you want to call data in both of the sliders, you have 2 ways to handle it.
Make your redux requests in HomePage.js component and bind the data to the other components.
When you get the data on BannerList.js component, your state will be updated. Just add the redux connection to your anotherslider.js component and get data when updated.
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeList);
Apart from all these options, you can also use react's Context API as Provider/consumer to distribute your data among small components... this will save you passing props to all small components and directly access the value in component using Context.Consumer .. moreover if you do not want to store this state in global redux store, context API will save you from it...

REST calls from a react component

I'm trying to replicate same code here with different JSON, but the data is not loading.
Please help, I'm not sure what is missing in the code.
import React from 'react';
export default class ItemLister extends React.Component {
constructor() {
super();
this.state = { items: [] };
}
componentDidMount() {
fetch('http://media.astropublications.com.my/api/drebar_landing.json')
.then(result=>result.json())
.then(items=>this.setState({items}));
}
render() {
return(
<ul>
{this.state.items.length ?
this.state.items.map(item=><li key={item.id}>{item.Title}</li>)
: <li>Loading...</li>
}
</ul>
)
}
}
Your api response contains an object ArticleObject and the ArticleObject has array of objects so you need to set the items.ArticleObject to the state.
Take a look at below solution for better understanding
componentDidMount() {
fetch('http://media.astropublications.com.my/api/drebar_landing.json')
.then(result=>result.json())
.then(items=>this.setState({items:items.ArticleObject}));
}