Axios api call doesn't accept parameters - javascript

I am trying to pass the following information to my dispatch function but the values are simply not begin recognized for some reason. They usually come out as undefined
My disptach call in my component:
methods: {
buscar(){
const formData = {
user: this.user,
password: this.password,
profile: this.profile
};
console.log('fomrdata: ',formData)
this.$store.dispatch('login', formData)
}
},
My method in store:
login(formData) {
console.log(formData)
},
All the values exist when i fill in my form and they show up in my component's console.log().

formData should be the second parameter in the action.
actions: {
login ({ commit }, formData) {
console.log(formData);
}
}

Related

my error object is undefined when i`m using rtk query with try/catch

first of all i want to apologize for my title. I just dont know how to describe my problem.
I am trying to get a bad response from my server and when I try to display that my object is undefined
I have a base query methods here:
export const accountSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
login: builder.mutation({
query: credentials => ({
url: 'account/login',
method: 'POST',
body: { ...credentials },
})
}),
register: builder.mutation({
query: credentials => ({
url: 'account/register',
method: 'POST',
body: { ...credentials },
})
})
})
})
My handle submit on register page ->
const [register, { isLoading, isError }] = useRegisterMutation();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const result = await register({ name, nickName, email, password }).unwrap();
setRegisterResponse(result);
} catch (error) {
setRegisterResponse(error);
}
}
And my logic to show it. When i use console.log(registerResponse) it returnes two logs in console - first object is empty, second object with properties ->
{
isError &&
<h2>
Ooops.. something went wrong:
{
console.log(registerRespnse)
}
</h2>
}
Error in google console
You shouldn't need to call a setRegisterResponse state setter, because that response will just be available for you:
// see data and error here
const [register, { isLoading, isError, data, error }] = useRegisterMutation();
As why it logs undefined once: first the query finishes with an error (which will rerender the component and already fill error I showed above and set isError) and then the Promise resolves and your custom code sets your response local state, which causes a second rerender (and only on the second render, response is set)

How to pass data with specific ID to backend route param?

I want to post a message to a backend route param with the current id.
How do I let the system know that I am passing this id?
Vuex action:
postMessage({commit}, payload, id) {
axios.post(`http://localhost:5000/channels/${id}/messages` ,payload)
.then((res) => {
commit(SET_POSTS, res.data)
})
}
This is posting the action but I need to pass the current channel id somehow. But the channel ID is in a different component?
postMessage() {
const postData = {
description: this.description,
timestamp: this.timestamp
};
this.$store.dispatch("postMessage", postData)
},
In a different component I have a channel list in my side menu, like discord for example and I display it like this
p.d-flex.align-items-center.channel-item(v-for="channel in channelName" :key="channel.id")
strong.hash.mr-3 #
| {{channel.channel_name}}
One of the primary benefits of Vuex is the ability to set state in one component and get it from another. In the other component, set some state like state.id. Then you can either pass that id to the action, or get it from state inside the action.
Here's an example of passing it:
Method
postMessage() {
const postData = {
id: this.$store.state.id,
description: this.description,
timestamp: this.timestamp
};
this.$store.dispatch("postMessage", postData)
}
Vuex actions always provide only 2 parameters, one for the context object (which contains commit, dispatch, etc.) and the payload. Change your action to:
Action
postMessage({ commit }, payload) {
axios.post(`http://localhost:5000/channels/${payload.id}/messages`, payload)
.then((res) => {
commit(SET_POSTS, res.data)
})
}
If you prefer, you can destructure the payload argument and use the spread operator to separate out the id from the rest:
Action
postMessage({ commit }, { id, ...payload }) {
axios.post(`http://localhost:5000/channels/${id}/messages`, payload)
.then((res) => {
commit(SET_POSTS, res.data)
})
}
You could also leave the id out of the payload and take it directly from state in the action:
Action
postMessage({ state, commit }, payload) {
axios.post(`http://localhost:5000/channels/${state.id}/messages`, payload)
.then((res) => {
commit(SET_POSTS, res.data)
})
}

How to login user to spring-security app using Vue.js?

Hi it's my first post on stack overflow. I want to separate back-end from front-end and create REST API using my Spring Boot app. I use spring-security to login. It use something called JSESSION_ID but how to login and authorize users using Vue.js? I want to make form for login to my service and authorize request with JSESSION_ID.
It's my first app in Vue.js. I try to use code from tutorials and docs but it didn't solve my problem. I also have issues with CORS.
export default {
name: 'Login',
data(){
return{
username: '',
password: '',
error: false
}
},
updated(){
if (localStorage.token){
this.$router.replace(this.$route.query.redirect || '/')
}
},
methods:{
login(){
this.$http.post('http://localhost:8080/login', { username: this.username, password: this.password })
.then(request => this.loginSuccessful(request))
.catch(() => this.loginFailed())
},
loginSuccessful (req) {
if (!req.data.token) {
this.loginFailed();
return
}
this.error = false;
localStorage.token = req.data.token;
this.$router.replace(this.$route.query.redirect || '/')
},
loginFailed () {
this.error = 'Login failed!';
delete localStorage.token
}
}
}
I expect to login and authorize users from Vue.js using REST Spring-Boot API.
The problem is that you try to pass the object { username: this.username, password: this.password } as the data to the request, but you do not specify the Content-Type, which probably defaults to 'text/html' or 'application/json'. You could try to first convert that into form data and then pass it to the request, here is an example with AXIOS:
login() {
let formData = new FormData();
formData.set("username", this.username);
formData.set("password", this.password);
AXIOS.post('/login', formData, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then((result) => {
this.loginSuccessful(result);
})
.catch((error) => {
this.loginFailed();
})
}
Perhaps it would also work without specifying the header, like AXIOS.post('/login', formData, null), haven't tried it.

VueX/VueJs : Execute code in component after async process

I'm trying to display a toast when a async request is finished.
I've implemented this process:
Single File Component calls updateUserProfile() actions in my VueX store
updateUserProfile() actions makes a outgoing HTTP request on a server using Axios
When succeeded, I use a mutation to update the user profile in my store and i would like to show a toast from my single file component.
Problem is that the response object is always undefined in my component. Where is my mistake ?
Error :
profile.vue?a62a:328 Uncaught (in promise) TypeError: Cannot read
property 'data' of undefined
at eval (profile.vue?a62a:328)
Store:
/*
* Action used to fetch user data from backend
*/
updateUserProfile ({commit, state}, userData) {
// Inform VueX that we are currently loading something. Loading spinner will be displayed.
commit('SET_IS_LOADING', true);
axiosBackend.put('/user/profile', userData, { headers: { Authorization: state.authString } } ).then(res => {
console.log('PUT /user/profile', res);
// Set user Data in VueX Auth store
commit('SET_USER_DATA', {
user: res.data.data
});
// Reset is Loading
commit('SET_IS_LOADING', false);
return res.data;
})
.catch(error => {
// Reset isLoading
commit('SET_IS_LOADING', false);
});
}
Component:
methods: {
// mix the getters into computed with object spread operator
...mapActions([
'updateUserProfile'
]),
// Function called when user click on the "Save changes" btn
onSubmit () {
console.log('Component(Profile)::onSaveChanges() - called');
const userData = {
firstName: this.firstname,
}
this.updateUserProfile(userData).then( (response) => {
console.log('COMPONENT', response);
if (response.data.status === 200) {
toastr.success("Your profile has been successfully updated.");
}
});
}
}
Well,
It would be better idea if You trigger the toast from the Vuex store itself as mentioned below.
callAddToCart: ({ commit }, payload) => {
axiosBackend.put('/user/profile', userData, { headers: { Authorization:
state.authString }}).then(response => {
commit("setLoading", false, { root: true });
payload.cartKey = response.key;
commit("setNotification", {
type: 'success',
title: `title`,
});
commit("ADD_TO_CART", payload);
});
},
and inside mutation you can have a general notification toast and you can pass type, message and title as below.
setNotification(state, {type, message, title}) {
state.flash = {
type,
title,
message
}
}
NOTE: Do not forget to load toast element at the root level in order to display in the UI.
Here is working example
Hope this helps!

Shared method of store fields

Motivation
I store user credentials in redux store. They are filled when user logs in. I would like to have reusable method to fetch data with user's username and password.
State / auth
const initState = {
isLoading: false,
user: undefined,
auth_err: false
};
My attempt
const fetchData = props => async (url, method, body) => {
try {
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + Base64.btoa(props.user.username + ":" + props.user.password)
},
body: body
});
console.log(response);
return response;
} catch (err) {
console.log(err);
}
};
const mapStateToProps = state => {
return {
user: state.auth.user
}
};
export const SENDREQUEST = connect(mapStateToProps)(fetchData);
Call
const response = await SENDREQUEST("http://localhost:8080/users", "GET");
But once I call it I get:
TypeError: Cannot call a class as a function
Is there any way at all to create such one?
Any help would be appreciated ♥
I am assuming that you know about redux and its middleware.
First of all the error comes from passing fetchData to the return value of connect : connect returns a function which is a HOC : takes a component, returns a component which is a class here that cannot be called as a function as you do.
A solution for your problem is to use mapDispatchToProps and a middleware, roughly as follow :
class LoginFormPresenter {
render () {
// render your login
return <form onSubmit={this.props.logUser}></form>
}
}
// This makes the LoginFormPresenter always receive a props `logUser`
const LoginFormConnector = connect((state => { user: state.user }), {
logUser: (e) => (
// create a credentials object by reading the form
const credentials = ...;
// return a valid redux action
return {
type: "LOGIN",
credentials
};
)
});
const LoginForm = LoginFormConnector(LoginFormPresenter);
// Create an ad hoc middleware
//
const middleware = ({ dispatch, getState }) => next => action => {
if (action.type === "LOGIN") {
// log your user
fetch()
.then(user => next({ type: "LOGIN", user }));
return next({ type: "PROCESSING_LOGIN" }); // indicate to redux that you are processing the request
}
// let all others actions pass through
return next(action);
};
So the mechanism works like this:
The LoginFormConnector will inject a props logUser into any component it is applied to. This props is a function wich dispatches an action with the credentials of your user. It will also inject a user props taken from the redux state for you to show your user.
Inside a redux middleware you catch the action and use your generic fetchData to process the request. When the request is resolved you dispatch the action to the reducer and update it. No data fetching occurs in the component itself, everything is handled at the middleware level.

Categories

Resources