How to Check Angular current route without hard-coded? - angular6

I want to check url
private m_Router: Router
if(this.m_Router.url == "create/xxx")
{
.....
}
I could achieve checking url and take action based on URL well with code above. But I have implemented this hard-coded.
May I take path from Router ?
I can not use private a_Router: ActivatedRoute
because it is not related with url.
The main problem is that when I am in create/xxx page, when I try to navigate create/xxx/yyy url, the component that has url create/xxx , is triggered again(ngOnInıt) so I want to check in ngOnInit() if this is a url that really belong to this page. I mean how can I read PATH variable from Router ?

constructor(private router: Router ) {
}
**Then call it's URL parameter:
**
console.log(this.router.url)
if(this.router.url==""){
}

Related

Angular 9 - Cannot find a differ supporting object 'getData()

I am getting this error trying to bind my control to its data. Here is some relevant code.
Template.
<tree-control [nodes]="getData"></tree-control>
Component.
public getData(): Observable<Array<any>> {
const assets: any = this.service.get('url', headers);
return assets;
}
Anything I have found so far is not helping. Any idea what's wrong with my code?
Thanks
First of all, you assign a function (getData) to the nodes property. I assume you want to assign the data from getData to it instead.
Secondly, the call to this.service.get is probably not being executed. Reason for that is that you do not subscribe to, what I assume, is a http-call that returns an Observable.
To fix this, you can do the following:
export class Foo {
nodeData: Observable<any>;
constructor(
private readonly service: YourService,
) {
this.nodeData = this._getData();
}
private _getData() {
return this.service.get(...);
}
}
Inside your template you can then subscribe and unsubscribe to the data automatically by using the async pipe.
<tree-control [nodes]="nodeData | async"></tree-control>
For all that to work I assume your service.get method returns an Observable.

Is there a way to print value in variable in angular4 component from console?

I save simple key in a variable in a component using angular 4, when the app closed every value will erased and i know it.
this is a simple sample :
export class LoginComponent implements OnInit {
data : any;
constructor() {
this.data = "Hello";
}
}
I just want to know is there a way using browser console to show value in this.data without console.log()?
Yes you can.
Start by finding some HTML that belongs to your component in your page. Then, inspect it.
In Chrome, you will see a $0 besides it. That's a variable reference.
Now, go into your console and type
ng.probe($0).componentInstance
This will log you your whole component, with the variables that are in it. You can simply give it a reference
const myRef = ng.probe($0).componentInstance
Then delete your component as you want, and log it again from the console directly
console.log(myRef) // or shorthand
myRef

Cannot recieve DATA from RESTFUL API using IONIC 2 generated provider

So, i'm currently studying Ionic 2 to make hybrid applications. I'm following a course on Udemy but the course's content about HTTP requests to WEB API's is obsolete(it's from the ionic 2 Beta). This is a long question but some of you's who are more experienced on the Ionic 2 framework can just skip to step 8 to save some time. Thanks a lot guys!
I'm trying to retrieve data from this URL:
https: //viacep.com.br/ws/01001000/json/.
It has a space after https:// because stackoverflow won't allot me to post more than one link.
But I'm missing something to save this data on a variable I created.
What I did to this point is:
1) I generated the provider which I called ConnectionService using the CLI ionic generator.
ionic g provider ConnectionService
2) Created a method called getCEP() inside the ConnectionService Provider, which makes an HTTP GET Request
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
/*
Generated class for the ConnectionService provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class ConnectionService {
constructor(public http: Http) {
console.log('Hello ConnectionService Provider');
}
getCep(): Promise<Response>{
let response: any = this.http.get("https://viacep.com.br/ws/01001000/json/");
console.log("Response: " + response);
let responsePromise: any = response.toPromise();
console.log("ResponsePromise: " + responsePromise);
return responsePromise;
}
}
P.S.: Here you can see i'm loggin in two steps of the request: The first one is the response before I turn it into a Promise, so I can return it to the page. The second one is after i cast it to a Promise using the toPromise() method.
3)In my view I have a button which has the (click) directive calling the method buscarCEP()
<ion-header>
<ion-navbar>
<ion-title>Teste</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<button (click)="buscarCep()">Request CEP</button>
</ion-content>
4.1) My TypeScript file has imported the ConnectionService Provider and named it ConnectionService.
4.2) I declared the ConnectionService inside the #Component directive under the "providers:" label
4.3) I create an instance of Connection Provider that I call conServ on the constructor's declaration. Also I created a variable called CEP, to store the data that I pull from it.
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { ConnectionService } from '../../providers/connection-service';
/*
Generated class for the MenuTest page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-menu-test',
templateUrl: 'menu-test.html',
providers: [ConnectionService]
})
export class MenuTestPage {
public CEP: any;
constructor(public navCtrl: NavController, public navParams: NavParams, public conServ: ConnectionService) {
}
6)Then I modify the method buscarCEP() so that it gets that conServe instance and calls the getCEP() method which makes an HTTP Request to the URL given above.
buscarCep(): void{
this.conServ.getCep().then(data =>{
console.log("DATA:" + data);
this.CEP = data;
}).catch(err => {
console.log("ERRO: " + err);
});
console.log("CEP: " + this.CEP);
}
PS.: As you can see, i'm logging three steps into the request: The data when the getCEP() method executes, a possible error called 'err' and by the end of it, the variable CEP that I created before and saved the data value to.
7)When I run the application and click on the button, I get the following screen with the console.logs:
Image of ionic page with snips of the Chrome console
8) As you can see, my logs are returning as follows:
8.1) The "Hello ConnectionService Provider" is from the console.log inside the provider's constructor, so the import of the provider is fine and it is being instantiated.
8.2) the "Response: [object Object]" is from the first console.log() inside the getCEP() method in the provider itself.
8.3) the "RespondePromise: [object Object]" is from the second console.log() inside the getCEP() method in the provider itself, after i casted the response to a Promise.
8.4)"CEP: undefined" comes from the console.log inside the buscarCEP() method, which is called after I click on the Request CEP Button
8.5)"DATA:Response with status: 200 OK for URL: https://viacep.com.br/ws/01001000/json/" comes from the console.log() inside the buscarCEP() method.
9) From this i'm taking that the getCEP() method is being able to connect to the URL, hence why the Response and ResponsePromise logs have an Object attached to them. Also the DATA log tells me that i recieved an OK Response from the server. My question is in regard to CEP: Undefined log. I can't seem to store that object in the variable I created.
I know that this is a long one but I wanted to lay all my cards on the board and explain everything as thoroughly as I could because i'm new to this framework.
Any help is appreciated, thank you for your time!
The Response object is stored in this.CEP. The issue is console.log(this.CEP) is called before the response from the HTTP request is returned within then.Promises are asynchronous.You can check the contents by doing console.log(this.CEP) within then.
So if you were to print the data in the html side, use safe navigation operator ?. e.g: {{CEP?.property}}.
A couple of issues with your code:
You should extract the json data from your response object. I suggest you do:
this.CEP = data.json();
If you want to print the contents of the object you can try console.log(JSON.stringify(data,null,2)).

Dynamic path segment OR 404

I have an app that needs to check with a backend API before rendering 404. The routing flow works something like this:
Request comes in to /{INCOMING_PATH}, and the application attempts to fetch and render data from api.com/pages/{INCOMING_PATH}.
If the API returns 404, then the app should return 404. If not, the data is rendered.
I'm not sold on using for this use case. {INCOMING_PATH} will be dynamic, potentially with slashes and extensions in the path. Is this possible to implement in React Router (with proper SSR behavior too)? If so, how should I proceed?
(This question was originally posted on github by another user. They were requested to post it here as it is a support request. But it doesn't seem they did. I am now stuck on exactly the same issue.)
I've solved this with the React Nested Status module.
I'm using https://github.com/erikras/react-redux-universal-hot-example so this code is geared towards that. See React Nested Status for a more generic solution.
Edits to server.js:
at the top
import NestedStatus from 'react-nested-status';
at the bottom replace:
const status = getStatusFromRoutes(routerState.routes);
if (status) {
res.status(status);
}
res.send('<!doctype html>\n' +
ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>));
with:
const repsonse = ReactDOM.renderToString(
<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>
);
const status = getStatusFromRoutes(routerState.routes);
if (status) {
res.status(status);
}
const nestedStatus = NestedStatus.rewind();
if (nestedStatus !== 200) {
res.status(nestedStatus);
}
res.send('<!doctype html>\n' + repsonse);
Then in what ever container/component you need to serve a 404 :
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import connectData from 'helpers/connectData';
import { fetchApiData } from 'redux/modules/foo/fetchApiData';
import { NotFound } from 'containers';
#connectData(null, (getReduxState, dispatch, state, params) => {
return dispatch(fetchApiData(params.fooId));
})
#connect(
(reduxState) => ({
fooData: reduxState.foo.data,
})
)
export default class ProductType extends Component {
static propTypes = {
fooData: PropTypes.object,
}
render() {
let content;
// ... whatever your api sends back to indicate this is a 404
if (!this.props.fooData.exists) {
content = <NotFound/>;
} else {
content = (
<div className={styles.productType}>
Normal content...
</div>
);
}
return content;
}
}
Finally replace /src/containers/NotFound/NotFound.js
import React, { Component } from 'react';
import NestedStatus from 'react-nested-status';
export default class NotFound extends Component {
render() {
return (
<NestedStatus code={404}>
<div className="container">
<h1>Error 404! Page not found.</h1>
</div>
</NestedStatus>
);
}
}
I'm not sure what kind of state implementation you are using. But, if you are using redux, then I think the simplest way is to use redux-simple-router. With it, your Routes are synchronized within your state, so you can dispatch action creators to change the router path. I would try to update satate with action creators instead of pushing the state directly from a component. The truth point must be always the state, in your case I would act as follows:
The component that requires to fetch the data will be subscribed to the "dataReducer" which is the isolated state part that this component should care about. Maybe the initial state of dataReducer is an empty array. Then, in componentWillMount you dispatch an action like: dispatch(fetchDataFromApi)) If the response code is 404, then in the action fetchDataFromApi you can dispatch another action, that is just an object like this one:
{type:SET_NOT_FOUND_ERROR}
That action will be handled by the reducer dataReducer, and will return a new state with an object (consider Immutability) that will have a property error, which will be a string with the reason, or whatever you want.
Then, in componentWillReceiveProps method, you, can check if the nextProps have or not have an error. If Error, you can render your error component, or even dispatch an action to go to the error page handled by react-router.
If no error, then you can dispatch an action (thanks to redux-simple-router) to go to the path y

Where to load the server data

I'm using the react-router and navigate to a component that gets an ID in the URL and has to use this ID to get data from the server with the help of an action.
At the moment I'm calling the action creator in the componentWillMount hook.
This works so far, but brings a problem.
In the render method I have to check, if myData really exists with all its attributes, before I can really render.
#connect(state => {myData: state.etc.myData})
export default class extends React.Component {
componentWillMount = () => {
this.props.dispatch(
ActionCreators.getData(this.props.params.id)
)
}
render() {
if (this.props.myData.hasNotLoaded) return <br/>
...
}
}
Is there another way to get data into the store before rendering without manual checks?
You can subscribe to router's onEnter hook and dispatch actions from where.
const store = configureStore()
const routing = (<Router>
<IndexRoute onEnter={()=>store.dispatch(myLoadDataActionCreator())}/>
</Router>)
So you can avoid setState from previous answer and don't tie up component with redux.
You should create a call back, for example:
_onChange() {
this.setState(myStore.getData());
}
Then in the following react functions do the following:
componentDidMount() {
myStore.addChangeListener(this._onChange);
},
componentWillUnmount() {
myStore.removeChangeListener(this._onChange);
}
I assume you're using the mixins for the react-router, if not, take a look at the docs for it, they have some useful functions that are worth looking at.
I don't think you will need that if logic in the render() method, react will handle that with the virtual dom management and know when to load it and the data.