How to fix JSON parse error in Vuex with localStorage - json

I have setup Vuex in Vue.js and using it to update the state. After building login functionality on it I am trying to store the token in localstorage but when I add localstorage to state it is throwing an error.
my current code:
import Vue from 'vue';
import Vuex from 'vuex';
import { getAPI } from '#/axios';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
accessToken: JSON.parse(localStorage.getItem('accessToken')) || null,
APIData: '',
},
mutations: {
// eslint-disable-next-line camelcase
updateStorage(state, { access_token }) {
// eslint-disable-next-line camelcase
state.accessToken = access_token;
localStorage.setItem('accessToken', JSON.stringify(access_token));
// axios.defaults.headers.common.Authorization = `Bearer ${access_token.access_token}`;
// sessionStorage.setItem('accessToken', access_token);
},
destroyToken(state) {
state.accessToken = null;
},
},
getters: {
loggedIn(state) {
return state.accessToken != null;
},
},
actions: {
userLogin(context, usercredentials) {
return new Promise((resolve, reject) => {
getAPI.post('/login', {
email: usercredentials.email,
password: usercredentials.password,
})
.then((response) => {
context.commit('updateStorage', { access_token: response.data.access_token });
resolve();
console.log(response.data.access_token);
})
.catch((error) => {
reject(error);
});
});
},
userLogout(context) {
if (context.getters.loggedIn) {
context.commit('destroyToken');
}
},
},
});

Since you're receiving raw encoding and creating an object wrapper for it in this format:
{ access_token: 'eyJ0eX...' }
You shouldn't destructure it in the mutation payload. Pass the whole object to localStorage if you're going to use JSON.parse:
updateStorage(state, access_token) {
state.accessToken = access_token;
localStorage.setItem('accessToken', JSON.stringify(access_token));
},

Related

how to solve "You may need an appropriate loader to handle this file type"?

I'm using react with typescript and redux-toolkit when I want to show the user who is logged in this error occurs error
here's the use Selector in layout.tsx:
const {user} = useSelector((state:any) => state.user);
and here's the display in html (also layout.tsx):
<Link className="anchor" to='/profile'>{user?.name}</Link>
my Reducer ,userSlice.tsx:
export const userSlice = createSlice({
name: "user",
initialState: {
user: null,
},
reducers: {
setUser: (state,action) => {
state.user= action.payload;
},
},
});
export const { setUser } = userSlice.actions;
and this a part of the protectedRoute.tsx the part which I want to retrieve the username:
const getUser = async () => {
try {
dispatch(showLoading());
const response = await axios.post(
"/api/users/user",
{ token: localStorage.getItem("token") },
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
dispatch(hideLoading());
if (response.data.success) {
dispatch(setUser(response.data.data));
} else {
navigate("/login");
}
} catch (error) {
dispatch(hideLoading());
navigate("/login");
}
};
useEffect(() => {
if (!user) {
getUser();
}
}, [user]);
if (localStorage.getItem("token")) {
return props.children;
} else {
return <Navigate to="/login" />;
}

Unable to populate json to FormArray. TypeError: data.map is not a function

I am receiving this json format from api and need to populate it into FormArray. But am getting TypeError: data.map is not a function. Below is the code snippet.
{
"data": [
{
"id": "ASR4324368",
"name": "TTTTT",
"amount": 100
},
{
"id": "GTH435435435",
"name": "AAAAA",
"amount": 500
}
]
}
getProductJson() {
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.subscribe(
(data: any[]) => {
this.productForm = this.fb.group({
product: this.fb.array(
data.map(datum => this.generateDatumFormGroup(datum))
)
});
},
error => {
console.log(error);
}
);
}
private generateDatumFormGroup(datum) {
return this.fb.group({
id: this.fb.control({ value: datum.id, disabled: false }),
productName: this.fb.control({ value: datum.name, disabled: false }),
productAmt: this.fb.control({ value: datum.amount, disabled: false }),
});
}
are you sure you get data? to check use pipe(tap)
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.pipe(tap(res=>{console.log(res)})) //<--add this line
.subscribe(....rest-of your code...)
NOTE: I feel strange your request (but really I don't know if is ok) I ususally use some like
this.httpClient.get('http://myapi/api/controller/action', { withCredentials: true })
Modified to the below and was working.
getProductJson() {
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.subscribe(
(data: any[]) => {
this.raw = data;
this.productObj = this.raw.data;
this.productForm = this.fb.group({
product: this.fb.array(
this.productObj.map(datum => this.generateDatumFormGroup(datum))
)
});
},
error => {
console.log(error);
}
);
}

Populating picker in react native through fetch from the server

I am trying to get picker values from the server to my react-native project. this is my JSON data. How do I fetch it for the picker component? I tried all d methods from web results. but I get only a blank screen. Kindly please help
{
"MFBasic": {
"SkinTones": "DARK,FAIR,VFAIR",
"Build": "SLIM,ATHLETIC,PLUMPY",
"Gender": "F,M,T",
"Genre": "ACTION,COMEDY,DRAMA",
"Languages": "ENG,HINDI,TAM",
"MediaModes": "ADS,MOVIES,SHORTFILMS",
"Tags": "BIKES,HOME,JEWELLARY"
},
"Result": "Successfully Loaded MF Basic Details",
"Code": 100
}
App.js
export default class App extends Component {
state = {
PickerValueHolder:[],
Gender:'',
}
componentDidMount() {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
}).then((response) => response.json())
.then((responseJson) => {
let PickerValueHolder = responseJson.MFBasic;
this.setState({ PickerValueHolder }); // Set the new state
}).catch((error) => {
console.error(error);
});
}
render() {
return (
<View style = {styles.MainContainer}>
{<Picker
selectedValue={this.state.Gender}
onValueChange={(itemValue, itemIndex) =>
this.setState({Gender:itemValue})} >
{ this.state.PickerValueHolder.map((item, key)=>
<Picker.Item label={item.Gender} value={item.Gender} key={key}/>
)}
</Picker>}
</View>
);
}
}
above code is my app.js file. but it returns nothing to the picker.help me please. Thank u.
Looking at the json from your API call
{
"MFBasic": {
"SkinTones": "DARK,FAIR,VFAIR",
"Build": "SLIM,ATHLETIC,PLUMPY",
"Gender": "F,M,T",
"Genre": "ACTION,COMEDY,DRAMA",
"Languages": "ENG,HINDI,TAM",
"MediaModes": "ADS,MOVIES,SHORTFILMS",
"Tags": "BIKES,HOME,JEWELLARY"
},
"Result": "Successfully Loaded MF Basic Details",
"Code": 100
}
The issue that is that you are trying to set a string where it needs an array. You can do it by doing something like this:
let genderString = responseJson.MFBasic.Gender;
let genderArray = genderString.split(',');
this.setState({ PickerValueHolder: genderArray });
let responseJson = {
"MFBasic": {
"SkinTones": "DARK,FAIR,VFAIR",
"Build": "SLIM,ATHLETIC,PLUMPY",
"Gender": "F,M,T",
"Genre": "ACTION,COMEDY,DRAMA",
"Languages": "ENG,HINDI,TAM",
"MediaModes": "ADS,MOVIES,SHORTFILMS",
"Tags": "BIKES,HOME,JEWELLARY"
},
"Result": "Successfully Loaded MF Basic Details",
"Code": 100
}
let genderString = responseJson.MFBasic.Gender;
let genderArray = genderString.split(',');
console.log(genderArray)
Because the items in your array are just strings you cannot access them by using item.Gender that won't work. You need to just access them using item.
I have created an example based on your code and implemented the change from above and fixed the Picker.Item component so it should render now. You can see the working code at the following snack https://snack.expo.io/#andypandy/picker-with-array-of-strings
import React from 'react';
import { Text, View, StyleSheet, Picker } from 'react-native';
import { Constants } from 'expo';
export default class App extends React.Component {
state = {
PickerValueHolder: [],
Gender: ''
}
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then((response) => response.json())
.then((responseJson) => {
let genderString = responseJson.MFBasic.Gender;
let genderArray = genderString.split(',');
this.setState({ PickerValueHolder: genderArray });
}).catch((error) => {
console.error(error);
});
}
render () {
console.log(this.state.PickerValueHolder)
return (
<View style={styles.container}>
{<Picker
selectedValue={this.state.Gender}
onValueChange={(itemValue, itemIndex) =>
this.setState({ Gender: itemValue })} >
{ this.state.PickerValueHolder.map((item, key) =>
<Picker.Item label={item} value={item} key={key}/>
)}
</Picker>}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8
}
});

How to pass dynamic attribute/parameter to openDialog?

I need to pass the following ID: 59dc921ffedff606449abef5 dynamically to MatDialog. For testing proposes I'am using it as hard coded ID.
Unfortunately all my searches and tries failed and I can't get the id dynamically into the function call. I tried also the #input feature, but it didn't help.
edit-dilog.component.ts:
export class EditDialogComponent implements OnInit {
dialogResult:string = '';
constructor(public dialog:MatDialog, public loginService:LoginService ){ }
ngOnInit() {}
openDialog() {
this.dialog.open(EditUserComponent, { data: '59dc921ffedff606449abef5' })
.afterClosed()
.subscribe(result => this.dialogResult = result);
}
}
edit-user.component.ts:
export class EditUserComponent implements OnInit {
public message:any [];
public resData: {};
constructor(public thisDialogRef: MatDialogRef<EditUserComponent>,
#Inject(MAT_DIALOG_DATA) public data: number,
public loginService: LoginService) { }
ngOnInit() {
this.loginService.getSingleUser(this.data)
.subscribe(data => {
this.resData = JSON.stringify(data);
})
}
onCloseConfirm() {
this.thisDialogRef.close('Confirm');
}
onCloseCancel() {
this.thisDialogRef.close('Cancel');
}
}
The ID is coming from JSON Response in a service login-service.ts:
getSingleUser(id) {
return this.http.get(environment.urlSingleUsers + '/' + id, this.options)
.map(res => {
console.log('RES: ' + JSON.stringify( res.json() ) );
return res.json();
}).catch( ( error: any) => Observable.throw(error.json().error || 'Server error') );
}
extractData(result:Response):DialogUserData[] {
return result.json().message.map(issue => {
return {
ID: issue._id,
Email: issue.email,
Name: issue.fullName
}
});
}
And here is where I do the call of openDialog():
<i class="material-icons" (click)="openDialog()">create</i>
For more clarification here is how the JSON Response comes:
"message": [
{
"_id": "59415f148911240fc812d393",
"email": "jane.doe#foo.de",
"fullName": "Jane Doe",
"__v": 0,
"created": "2017-06-14T16:06:44.457Z"
},
{
"_id": "5943b80be8b8b605686a67fb",
"email": "john.doe#foo.de",
"fullName": "John Doe",
"__v": 0,
"created": "2017-06-16T10:50:51.180Z"
}
]
I just did something similar, though I'm a little bit confused by how you name the components (seems should be the other way around).
You can try: fetch the data (user) first and then (actually) open the dialog in your controlling component:
edit-dialog.component.ts:
openDialog(id: string) {
this.loginService.getSingleUser(id)
.subscribe(user=> {
const dialogRef = this.dialog.open(EditUserComponent, {
data: user
});
dialogRef.afterClosed().subscribe(result => {
console.log(`Dialog result: ${result}`);
});
});
}
You can then access the dialog data (user) to render the dialog view:
edit-user.component.ts:
ngOnInit() {
console.log(this.data);
}
In this way, you can pass the id dynamically:
<i class="material-icons" (click)="openDialog(id)">create</i>
where the id can be a member of your controlling component.

Can't access subscribe method in unit-test

I'm experiencing a very strange issue on a simple unit-test of a simple service get method. I'm using Angular 4 and cli so karma/jasmine for testing.
My service method:
getAccounts(): Observable<ApiData> {
return this.authHttp.get('../../assets/mock_data/productsOverview.json')
.map(
data => {
return JSON.parse(data['_body']);
},
err => {
return err;
}
);
}
And here is my test case:
import { TestBed, inject, async } from '#angular/core/testing';
import { Http, BaseRequestOptions, RequestOptions, HttpModule, ConnectionBackend } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
import { AuthHttp, AuthConfig } from 'angular2-jwt';
import { encodeTestToken } from 'angular2-jwt/angular2-jwt-test-helpers';
import { AppModule } from '../app.module';
import { PersonalAccountsService, ApiData } from './personal-accounts.service';
import { Observable } from 'rxjs/Observable';
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
headerName: 'Authorization',
headerPrefix: 'Bearer',
tokenName: 'token',
tokenGetter: (() => localStorage.getItem('token')),
globalHeaders: [
{ 'Content-Type': 'application/json' },
{ 'Ocp-Apim-Subscription-Key': localStorage.getItem('key') }],
}), http, options);
}
const MyMockedService = {
method: () => { }
}
describe('PersonalAccountsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
PersonalAccountsService,
BaseRequestOptions,
MockBackend,
{
provide: Http,
useFactory: (mockBackend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(mockBackend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions],
},
{
provide: AuthHttp,
useFactory: (http) => {
return new AuthHttp(new AuthConfig({
tokenName: 'token',
tokenGetter: (() => encodeTestToken(this)),
globalHeaders: [{ 'Content-Type': 'application/json' }]
}), http);
},
deps: [Http],
},
],
imports: [
HttpModule
],
});
});
it('should be created', inject([PersonalAccountsService],
(service: PersonalAccountsService) => {
expect(service).toBeTruthy();
}));
it('identification', async(
inject(
[PersonalAccountsService],
(service: PersonalAccountsService) => {
console.log('ENTERS HERE');
service.getAccounts().subscribe(
data => {
console.log('NOT ENTERING HERE');
},
err => {
console.log('NOT ENTERING HERE');
},
() => {
console.log('NOT ENTERING HERE')
}
);
}
)
));
});
Why this is happening? I'm trying to figure it our for a long time and I cannot even take an error to dive deeper.
The test likely performs requests but they weren't mocked with MockBackend.
The fact that code relies on third-party services (AuthHttp) makes it integration test rather than unit test.
To keep it as isolated as possible, every unit but tested unit should be mocked or stubbed. The service can be tested in isolation (in this case DI is not tested) or with TestBed:
beforeEach(() => {
const authHttpMock = jasmine.createSpyObj('authHttp', ['get']);
TestBed.configureTestingModule({
providers: [
{ provide: AuthHttp, useValue: authHttpMock }
...
});
it('...', async(inject([PersonalAccountsService, AuthHttp], async (service, authHttpMock) => {
const responseMock = Observable.of({ _body: ... });
authHttpMock.get.and.returnValue(responseMock);
const accounts$ = service.getAccounts();
expect(authHttpMock.get).toHaveBeenCalledWith(...);
const accounts = await accounts$.toPromise();
expect(accounts)...
...