NativeScript and Observables - nativescript

I'am currently a rookie to Nativescript and Angular. I've created a API using laravel and it works fine. Now I'am trying to connect and fetch data from my API in NativeScript/Angular. I've followed this tutorial as guideline Alex Ziskind.
My API is build with PHP in Laravel and my calls works fine in Postman. I'am also capable of getting som data, but I cant return it in the HTML.
My service
export public ItemService {
getItems():Observable<Item[]> {
const authToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIyIiwianRpIjoiZmIzYjJmYzg3MWY2YTc5ZjVjMTM3NDNmMDllNGUwNzYwZDkyODljMmVjNTE3NGZiNDMzZTRjMGQ0MjBjYTJmYjlhMGQ1ZmFjNTQ1NmQ3ODkiLCJpYXQiOjE1OTA2NTAyMjksIm5iZiI6MTU5MDY1MDIyOSwiZXhwIjoxNjIyMTg2MjI5LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.Y3kidP6TP__DrwBDcGuk6M4p76INEdxG8UWrdakfkfcjCOlmHA0pb7a8vTvRQl2WLA_gwNWD4qA64ToOZb1YxkWCe8ESBTRDBg9Xq3DbSsZzlBZb9v8zS8PEeJVnfMtmxVIJb8IEU82DYGbpky-XdDfn67ge6fM3jTvwyivthlhaQLkjsh8e3VKlUx0P8lSxoHVw-N0369otRU6X0CTghl5lg9Khru4AtdJIBL3AOQAFEZmpzAGg9xZkvY923VkgkBHXt-adfvBwG2ZP0UhUVht-aiKK2z9HlR0eQ_-eqYlo-fqmTAE0U1k5ET99jbap8xO0dXJfdYVF0cAJ7p6FNjMoougwR89kz2xCcUHyFnPli3HcZx7j8IKDhqvneL8oWjaJuO41z1O69qsbk7_g8iLVI5vQlv6slrIe2YSbABkHzzCGndFX-smZkugB8aNmoRGpX8RJ5y5HxE6pJG8nn8CYih5ednDlWaTUBGk0p4zpck2z8788zyX41sPdB1oqR2gO0_CL-pBjCdTgDYXi_hy49_SO_4Vsf8lPL7vyhhvv7w_KgV7Jc7ju3Xm4HRLUG56K8CMy1KEfVuTDYs0gnybuFolfv2haeVgc_2h2A65O5nuUZg_RpePrSBZEftLsITWa3lUvnF380_htio-Zp3gXs3INoH7ms5KdTPt3mZ8";
const URL = "http://10.0.2.2:8000/api/source";
/*return this.http.get<Item[]>(
URL,
{ headers: new HttpHeaders().append("Authorization", `Bearer ${authToken}`) }
)*/
const res = this.http.get<Item[]>(
URL,
{ headers: new HttpHeaders().append("Authorization", `Bearer ${authToken}`) }
)
console.log()
return res;
}
getItem(id) { }
/*
getItem(id: number): Item {
return this.items.filter((item) => item.id === id)[0];
}
*/
}
My component
export class ItemsComponent implements OnInit {
public items$: Observable<Item[]>;
constructor(private itemService: ItemService) { }
ngOnInit(): void {
this.itemService.getItems();
console.log(this.itemService.getItems())
}
}
My Template
<StackLayout class="page">
<ListView height="300" [items]="items$ | async" class="list-group">
<ng-template let-item="item">
<label [text]="item.data.first_name" class="list-group-item"></label>
</ng-template>
</ListView>
</StackLayout>
Terminal

Since this.itemService.getItems() returns an observable you will either have to subscribe to it in your typescript file or use the async pipe on your template.
Using subscribe:
items;
constructor() {
this.itemService.getItems().subscribe(res => {
this.items = res;
})
}
// in your template (Label here is just an example)
<Label [text]="items"></Label>
Using async:
items$ = this.itemService.getItems();
// in your template (Label here is just an example of how you would use the async pipe)
<Label [text]="items$ | async"></Label>

Related

Nativescript Listview showing nothing

I have a minimalist Nativescript hello world application. It has just 2 screens, 'Login' and 'List'.
Here is the flow:
User presses the login button in first screen.
Second screen is shown, which is suppose to show the list of names; but which shows nothing.
If I type even a single character in text field, it shows the list.
I have been scouring over Stack Overflow and Github, it seems the problem others are facing is a bit complicated, like "list not getting updated after http call" etc.
So it seems I am making some obvious mistake here, because this basic scenario should 'just work'. But that small mistake alludes me.
Here is my login file:
/*login.component.ts*/
import { Component } from "#angular/core";
import firebase = require("nativescript-plugin-firebase");
import * as Rx from "rxjs";
import { MyFireLoginService } from '../../mobile-fire/fire-login.service'
import { Router } from "#angular/router";
import { Observable } from "rxjs/Observable";
#Component({
selector: "login",
templateUrl: './pages/login/login.component.html',
styleUrls: ['./pages/login/login.component.css']
})
export class LoginComponent {
email: string = 'user1#site.com';
password: string = 'password';
user: Observable<any>;
constructor(private fl: MyFireLoginService, private router: Router) {
this.email = 'user1#site.com';
this.password = 'password';
this.user = fl.authState;
this.watchUser();
}
watchUser(): void {
this.user.subscribe((usr) => {
if (usr.uid) {
this.router.navigate(["/list"]);
}
})
}
login(): void {
this.fl.loginWithEmail(this.email, this.password)
}
}
and list file:
import { Component } from "#angular/core";
import firebase = require("nativescript-plugin-firebase");
import * as Rx from "rxjs";
import { MyFireLoginService } from '../../mobile-fire/fire-login.service'
import { Router } from "#angular/router";
import { Observable } from "rxjs/Observable";
#Component({
selector: "list",
templateUrl: './pages/list/list.component.html',
styleUrls: ['./pages/list/list.component.css']
})
export class ListComponent {
items: any[] = [];
user: Observable<any>;
constructor(private fl: MyFireLoginService,
private router: Router) {
this.user = fl.authState;
this.watchUser();
this.items = [{
name: 'aks1'
}, {
name: 'aks2'
}, {
name: 'aks3'
}]
}
watchUser(): void {
this.user.subscribe((usr) => {
if (!usr.uid) {
this.router.navigate(["/"]);
}
})
}
private textChanged(e: any): void {
console.log(e.value);
// console.dir(this.items);
}
logout() {
this.fl.logout()
}
}
list.component.html
<ActionBar title="List" class="action-bar"></ActionBar>
<StackLayout>
<Button class="submit-button" text="Logout" (tap)="logout()"></Button>
<TextField hint="empty field for testing.." (textChange)="textChanged($event)"></TextField>
<Label *ngFor="let item of items" [text]="item.name"></Label>
<!-- <GridLayout>
<ListView id="list-of-items" [items]="items" class="small-spacing">
<ng-template let-item="item">
<Label [text]="item.name" class="medium-spacing"></Label>
</ng-template>
</ListView>
</GridLayout> -->
</StackLayout>
login.component.html
<ActionBar title="Login" class="action-bar"></ActionBar>
<StackLayout>
<Button class="submit-button" text="Sign in" (tap)="login()"></Button>
<Label text="Hello world"></Label>
</StackLayout>
EDIT: Here are the log for the life-cycle events of two components:
JS: LOGIN:ngDoCheck called
JS: LOGIN:ngAfterContentChecked called
JS: LOGIN:ngAfterViewChecked called
JS: Auth state changed.
JS: a <==== This is me typing 'a' in the textbox of LIST component
JS: LOGIN:ngDoCheck called
JS: LOGIN:ngAfterContentChecked called
JS: LOGIN:ngAfterViewChecked called
JS: LIST:ngOnInit called
JS: LIST:ngDoCheck called
JS: LIST:ngAfterContentInit called
JS: LIST:ngAfterContentChecked called
JS: LIST:ngAfterViewChecked called
What I find strange is that List component's init is not called until I type 'a' in the textbox inside List component. Also, LOGIN component's life-cycle events are called even after is it gone out of view.
Update1: I followed the tutorial on nativescript.org. The code there seems to be working fine. I suspect, there is something wrong with inclusion of firebase plugin. Will update when I know more.
Update2: I stubbed parts of firebase api I am using, it worked fine with dummy APIs.

admin on rest send extra params to rest call

i have upload button inside create form, on button click handler i will upload image to cloud and on upload success i get image url. i need to pass this image url to rest api. this is my sample code.
When i submit my form i need to send image url as parameter.
Can anyone help me.
Here is my code:
<SimpleForm label="Create Artist">
<TextInput source="name" label="Name" />
<FlatButton style={styles.button} label="Upload Image" primary onClick={this.handleClick} />
</SimpleForm>
this.handleClick = () => {
cloudinary.openUploadWidget({
cloud_name: 'demo',
upload_preset: 'sh3432',
cropping: 'server'
}, function(error, result) {
return result;
});
};
You'll have to implement a custom input for that.
Something like (haven't tested it):
class UploadPictureInput extends Component {
handleClick = () => {
cloudinary.openUploadWidget({
cloud_name: 'demo',
upload_preset: 'sh3432',
cropping: 'server'
}, (error, result) => {
this.props.input.onChange(result);
});
}
render() {
return (
<FlatButton
style={styles.button}
label="Upload Image"
primary
onClick={this.handleClick}
/>
);
}
}
And use this input in your form.

Angular2/4 - model driven form - asynchronous custom validator not working

I've a problem getting a custom async validator to work. My approach is as follows.
Component:
import {Component, OnInit} from "#angular/core";
import {FormGroup, FormBuilder, Validators} from "#angular/forms";
import {User} from "./user";
import {EmailValidators} from "./emailValidators";
#Component({
selector: '<userform></userform>',
templateUrl: 'app/users/userform.component.html',
})
export class UserFormComponent implements OnInit{
public myForm: FormGroup;
constructor(private _fb: FormBuilder) {}
ngOnInit() {
this.myForm = this._fb.group({
name: ['', [<any>Validators.required]],
email: ['', Validators.compose([
<any>EmailValidators.emailFormat,
<any>Validators.required
]), EmailValidators.shouldBeUnique], // Async validator
address: this._fb.group({
street: ['', <any>Validators.required],
zipCode: ['']
})
});
}
// save() and other methods here...
}
Validator Class:
import {FormControl} from "#angular/forms";
export class EmailValidators {
static shouldBeUnique(control: FormControl) {
console.log("shouldBeUnique called");
return new Promise((resolve, reject) => {
setTimeout(function () {
if (control.value == "m#m.de") {
console.log("shouldBeUnique TRUE");
resolve({shouldBeUnique: true});
} else {
console.log("shouldBeUnique NULL");
resolve(null);
}
}, 1000);
});
}
static emailFormat(control: FormControl) {
var value = <string> control.value;
var regX = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!new RegExp(regX).test(value)) {
console.log("emailFormat: True", value)
return {emailFormat: true};
}
return {emailFormat: null}; // if validation passes return should be null
}
}
HTML:
<div class="form-group">
<label for="email">Email</label>
<input
id="email"
type="text"
class="form-control"
formControlName="email"/>
<div *ngIf="myForm.controls.email.errors.required"
class="alert alert-danger">Email is required {{ myForm.controls.email.errors | json }}</div>
<div *ngIf="myForm.controls.email.errors.emailFormat"
class="alert alert-danger">Email Format should be something like 'yourname#some-domain.com' {{ myForm.controls.email.errors | json }}</div>
<div *ngIf="myForm.controls.email.errors.shouldBeUnique"
class="alert alert-danger">shouldBeUnique {{ myForm.controls.email.errors | json }}</div>
</div>
Required validator works fine, the custom emailFormat validator works fine as well, the divs are kicking in and out where they should and even the shouldBeUnique validator works if its implemented as a standard validator.
But it does not as implemented above. The static method shouldBeUnique from the validator class is not even called. So - I assume the problem is somewhere in the components formGroup/formControl part. Please help.
Update
After testing various Angular-Versions (currently CLI/ 4.1.3) I found the following Error in the console:
email: FormControl
asyncValidator: function (control)
arguments: [Exception: TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context. at function.remoteFunction (<anonymous>:2:14)]
caller: (...)
Update
...actually the same error appears for sync-validators but these are working fine. While many tutorials give the impression that async validation in NG is an easy task I also read this: https://kahlillechelt.com/asynchronous-validation-with-angular-reactive-forms-1a392971c062
Confusing.

Console error whilst waiting for API response - React/Redux

I am fetching data from a remote API in componentDidMount:
componentDidMount() {
this.props.fetchRemoteData('photos')
}
And then the received data is passed to my component props in mapStateToProps, using a selector to filter a specific object from the received array:
const mapStateToProps = (state, { params }) => {
const photoId = parseInt(params.photoId)
return {
singlePhoto: getSinglePhoto(state.filteredList.photos.jsonArray, photoId),
isFetching: state.filteredList.photos.isFetching
}
}
The content renders, but there is a split second before that, where it seems to be trying to the render the content before the data is successfully retrieved, which brings up the following error in the console:
Uncaught TypeError: Cannot read property 'charAt' of undefined
undefined is here referring to this.props.singlePhoto. But when singlePhoto receives the data payload the content renders.
Here is my container component:
class PhotoSingle extends Component {
componentDidMount() {
this.props.fetchRemoteData('photos')
}
render() {
const {singlePhoto, isFetching} = this.props
const photoTitle = capitalizeFirstLetter(singlePhoto.title)
return (
<div>
<PhotoSingleImg singlePhoto={singlePhoto} photoTitle={photoTitle} isFetching={isFetching}/>
</div>
)
}
}
const mapStateToProps = (state, { params }) => {
const photoId = parseInt(params.photoId)
return {
singlePhoto: getSinglePhoto(state.filteredList.photos.jsonArray, photoId),
isFetching: state.filteredList.photos.isFetching
}
}
import * as actions from '../actions/actionCreators'
PhotoSingle = connect(mapStateToProps, actions)(PhotoSingle)
export default PhotoSingle;
And my presentational component:
const PhotoSingleImg = ({ singlePhoto, photoTitle, isFetching }) => {
if (isFetching) {
return <h4>Fetching data...</h4>
}
return (
<div>
<h1>Single Photo</h1>
<h3>Title</h3>
<hr />
<img className='single-photo' src={singlePhoto.url} />
<p>Album ID: {singlePhoto.albumId} | Photo ID: {singlePhoto.id}</p>
</div>
)
}
export default PhotoSingleImg;
I'm unsure how to make it so the content will only attempt to render after I the API response has been received.
Any help appreciated.
Have you defined initial state in redux store?
You can try this way:
return singlePhoto ?
(<div>
<h1>Single Photo</h1>
<h3>Title</h3>
<hr />
<img className='single-photo' src={singlePhoto.url} />
<p>Album ID: {singlePhoto.albumId} | Photo ID: {singlePhoto.id}</p>
</div>) : null

How to set initialValues based on async source such as an ajax call with redux-form

On the official pages and in the GitHub issues for redux-form there are more than one example of how to work with initialValues however I cannot find a single one that focuses on explaining how initialValues can be set in response to an asynchronous source.
The main case that I have in mind is something like a simple CRUD application where a user is going to edit some entity that already exists. When the view is first opened and the redux-form component is mounted but before the component is rendered the initialValues must be set. Lets say that in this example that the data is loaded on demand when the component is first mounted and rendered for the first time. The examples show setting initialValues based on hard coded values or the redux store state but none that I can find focus on how to set the initialValues based on something async like a call to XHR or fetch.
I'm sure I'm just missing something fundamental so please point me in the right direction.
References:
Initializing Form State
Handling form defaults
What is the correct way to populate a dynamic form with initial data?
EDIT: Updated Solution from ReduxForm docs
This is now documented in the latest version of ReduxForm, and is much simpler than my previous answer.
The key is to connect your form component after decorating it with ReduxForm. Then you will be able to access the initialValues prop just like any other prop on your component.
// Decorate with reduxForm(). It will read the initialValues prop provided by connect()
InitializeFromStateForm = reduxForm({
form: 'initializeFromState'
})(InitializeFromStateForm)
// now set initialValues using data from your store state
InitializeFromStateForm = connect(
state => ({
initialValues: state.account.data
})
)(InitializeFromStateForm)
I accomplished this by using the redux-form reducer plugin method.
The following demos fetching async data and pre-populating a user form with response.
const RECEIVE_USER = 'RECEIVE_USER';
// once you've received data from api dispatch action
const receiveUser = (user) => {
return {
type: RECEIVE_USER,
payload: { user }
}
}
// here is your async request to retrieve user data
const fetchUser = (id) => dispatch => {
return fetch('http://getuser.api')
.then(response => response.json())
.then(json => receiveUser(json));
}
Then in your root reducer where you include your redux-form reducer you would include your reducer plugin that overrides the forms values with the returned fetched data.
const formPluginReducer = {
form: formReducer.plugin({
// this would be the name of the form you're trying to populate
user: (state, action) => {
switch (action.type) {
case RECEIVE_USER:
return {
...state,
values: {
...state.values,
...action.payload.user
}
}
default:
return state;
}
}
})
};
const rootReducer = combineReducers({
...formPluginReducer,
...yourOtherReducers
});
Finally you include you combine your new formReducer with the other reducers in your app.
Note The following assumes that the fetched user object's keys match the names of the fields in the user form. If this is not the case you will need to perform an additional step on the data to map fields.
By default, you may only initialize a form component once via initialValues. There are two methods to reinitialize the form component with new "pristine" values:
Pass a enableReinitialize prop or reduxForm() config parameter set to true to allow the form the reinitialize with new "pristine" values every time the initialValues prop changes. To keep dirty form values when it reinitializes, you can set keepDirtyOnReinitialize to true. By default, reinitializing the form replaces all dirty values with "pristine" values.
Dispatch the INITIALIZE action (using the action creator provided by redux-form).
Referenced from : http://redux-form.com/6.1.1/examples/initializeFromState/
Could you fire the dispatch on componentWillMount(), and set the state to loading.
While it is loading, render a spinner for example and only when the request returns with the values, update the state, and then re-render the form with the values??
Here is minimal working example on how to set initialValues based on async source.
It uses initialize action creator.
All values from initialValues shouldn't be undefined, or you will get an infinite loop.
// import { Field, reduxForm, change, initialize } from 'redux-form';
async someAsyncMethod() {
// fetch data from server
await this.props.getProducts(),
// this allows to get current values of props after promises and benefits code readability
const { products } = this.props;
const initialValues = { productsField: products };
// set values as pristine to be able to detect changes
this.props.dispatch(initialize(
'myForm',
initialValues,
));
}
While this method may not be the best solution, it works well enough for my needs:
AJAX request to API on entry
Initializes form with data when request has been fulfilled or displays a server error
Resetting form will still reset to initial seed data
Allows the form to be reused for other purposes (for example, a simple if statement could bypass setting initial values): Add Post and Edit Post or Add Comment and Edit Comment...etc.
Data is removed from Redux form on exit (no reason to store new data in Redux since it's being re-rendered by a Blog component)
Form.jsx:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { browserHistory, Link } from 'react-router';
import { editPost, fetchPost } from '../../actions/BlogActions.jsx';
import NotFound from '../../components/presentational/notfound/NotFound.jsx';
import RenderAlert from '../../components/presentational/app/RenderAlert.jsx';
import Spinner from '../../components/presentational/loaders/Spinner.jsx';
// form validation checks
const validate = (values) => {
const errors = {}
if (!values.title) {
errors.title = 'Required';
}
if (!values.image) {
errors.image = 'Required';
}
if (!values.description) {
errors.description = 'Required';
} else if (values.description.length > 10000) {
errors.description = 'Error! Must be 10,000 characters or less!';
}
return errors;
}
// renders input fields
const renderInputField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} className="form-details complete-expand" placeholder={label} type={type}/>
{touched && error && <div className="error-handlers "><i className="fa fa-exclamation-triangle" aria-hidden="true"></i> {error}</div>}
</div>
</div>
)
// renders a text area field
const renderAreaField = ({ textarea, input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<textarea {...input} className="form-details complete-expand" placeholder={label} type={type}/>
{touched && error && <div className="error-handlers"><i className="fa fa-exclamation-triangle" aria-hidden="true"></i> {error}</div>}
</div>
</div>
)
class BlogPostForm extends Component {
constructor() {
super();
this.state = {
isLoaded: false,
requestTimeout: false,
};
}
componentDidMount() {
if (this.props.location.query.postId) {
// sets a 5 second server timeout
this.timeout = setInterval(this.timer.bind(this), 5000);
// AJAX request to API
fetchPost(this.props.location.query.postId).then((res) => {
// if data returned, seed Redux form
if (res.foundPost) this.initializeForm(res.foundPost);
// if data present, set isLoaded to true, otherwise set a server error
this.setState({
isLoaded: (res.foundPost) ? true : false,
serverError: (res.err) ? res.err : ''
});
});
}
}
componentWillUnmount() {
this.clearTimeout();
}
timer() {
this.setState({ requestTimeout: true });
this.clearTimeout();
}
clearTimeout() {
clearInterval(this.timeout);
}
// initialize Redux form from API supplied data
initializeForm(foundPost) {
const initData = {
id: foundPost._id,
title: foundPost.title,
image: foundPost.image,
imgtitle: foundPost.imgtitle,
description: foundPost.description
}
this.props.initialize(initData);
}
// onSubmit => take Redux form props and send back to server
handleFormSubmit(formProps) {
editPost(formProps).then((res) => {
if (res.err) {
this.setState({
serverError: res.err
});
} else {
browserHistory.push(/blog);
}
});
}
renderServerError() {
const { serverError } = this.state;
// if form submission returns a server error, display the error
if (serverError) return <RenderAlert errorMessage={serverError} />
}
render() {
const { handleSubmit, pristine, reset, submitting, fields: { title, image, imgtitle, description } } = this.props;
const { isLoaded, requestTimeout, serverError } = this.state;
// if data hasn't returned from AJAX request, then render a spinner
if (this.props.location.query.postId && !isLoaded) {
// if AJAX request returns an error or request has timed out, show NotFound component
if (serverError || requestTimeout) return <NotFound />
return <Spinner />
}
// if above conditions are met, clear the timeout, otherwise it'll cause the component to re-render on timer's setState function
this.clearTimeout();
return (
<div className="col-sm-12">
<div className="form-container">
<h1>Edit Form</h1>
<hr />
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<Field name="title" type="text" component={renderInputField} label="Post Title" />
<Field name="image" type="text" component={renderInputField} label="Image URL" />
<Field name="imgtitle" component={renderInputField} label="Image Description" />
<Field name="description" component={renderAreaField} label="Description" />
<div>
<button type="submit" className="btn btn-primary partial-expand rounded" disabled={submitting}>Submit</button>
<button type="button" className="btn btn-danger partial-expand rounded f-r" disabled={ pristine || submitting } onClick={ reset }>Clear Values</button>
</div>
</form>
{ this.renderServerError() }
</div>
</div>
)
}
}
BlogPostForm = reduxForm({
form: 'BlogPostForm',
validate,
fields: ['name', 'image', 'imgtitle', 'description']
})(BlogPostForm);
export default BlogPostForm = connect(BlogPostForm);
BlogActions.jsx:
import * as app from 'axios';
const ROOT_URL = 'http://localhost:3001';
// submits Redux form data to server
export const editPost = ({ id, title, image, imgtitle, description, navTitle }) => {
return app.put(`${ROOT_URL}/post/edit/${id}?userId=${config.user}`, { id, title, image, imgtitle, description, navTitle }, config)
.then(response => {
return { success: response.data.message }
})
.catch(({ response }) => {
if(response.data.deniedAccess) {
return { err: response.data.deniedAccess }
} else {
return { err: response.data.err }
}
});
}
// fetches a single post from the server for front-end editing
export const fetchPost = (id) => {
return app.get(`${ROOT_URL}/posts/${id}`)
.then(response => {
return { foundPost: response.data.post}
})
.catch(({ response }) => {
return { err: response.data.err };
});
}
RenderAlert.jsx:
import React, { Component } from 'react';
const RenderAlert = (props) => {
const displayMessage = () => {
const { errorMessage } = props;
if (errorMessage) {
return (
<div className="callout-alert">
<p>
<i className="fa fa-exclamation-triangle" aria-hidden="true"/>
<strong>Error! </strong> { errorMessage }
</p>
</div>
);
}
}
return (
<div>
{ displayMessage() }
</div>
);
}
export default RenderAlert;
Reducers.jsx
import { routerReducer as routing } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
form: formReducer,
routing
});
export default rootReducer;
use this :
UpdateUserForm = reduxForm({
enableReinitialize: true,
destroyOnUnmount: false,
form: 'update_user_form' // a unique identifier for this form
})(UpdateUserForm);
UpdateUserForm = connect(
(state) => ({
initialValues: state.userManagment.userSingle
})
)(UpdateUserForm);
export default UpdateUserForm;

Resources