I'm trying to use Meteor.call() and pass two variables in to complete the method
Template.RegisterForm.events({
'submit form': function(event) {
event.preventDefault();
var emailVar = event.target.registerEmail.value;
var passwordVar = event.target.registerPassword.value;
Meteor.call('registerUser', emailVar, passwordVar )
}
});
However when I call the method, emailVar and passwordVar do not pass through.
registerUser: function (email, password) {
var id = Accounts.createUser({
email: email,
password: password
});
}
they come up undefined??
You're calling the Meteor method fine,
var emailVar = event.target.registerEmail.value;
var passwordVar = event.target.registerPassword.value;
is likely your problematic code. event.target refers to the DOM element that initiated the event, in this case being the form. In turn, registerEmail and registerPassword will be undefined
See
https://jsfiddle.net/fqp3a1mq/ for an overview on using jQuery to grab your form data.
In the context of your specific issue, a clean solution is:
Template.form.events({
'submit form'(event) {
const $form = $(event.target);
const formData = $form.serializeArray();
const params = {};
event.preventDefault();
// loop over our form data and create a params object for our method
formData.forEach(data => {
params[data.name] = data.value;
});
Meteor.call('methodName', params);
},
});
Meteor.methods({
methodName(params) {
...
},
});
With this approach, if you have an input named registerEmail, then it will exist as params.registerEmail in your Meteor method.
Hope this helps.
Related
I was trying to make an app which lists a user's repositories from github using github API, however I'm having a big problem with fetching data from all pages (so far I can only get repos from one page). I tried to fix it by using an async/await function (instead of Promise), but it's also my first time using vue3 and I have no idea how to have a function inside of the setup() method.
The current code is here:
https://github.com/agzpie/user_repos
My try at using async/await, which didn't work:
import ListElement from "./components/ListElement";
import { ref, reactive, toRefs, watchEffect, computed } from "vue";
export default {
name: "App",
components: {
ListElement,
},
setup() {
const name = ref(null);
const userName = ref(null);
const state = reactive({ data: [] });
let success = ref(null);
const userNameValidator = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i;
const split1 = reactive({ spl1: [] });
const split2 = reactive({ spl2: [] });
async function myFetch() {};
/*
* Check for input in the form and then fetch data
*/
watchEffect(() => {
if (!userName.value) return;
if (!userNameValidator.test(userName.value)) {
console.log("Username has invalid characters");
return;
}
let hasNext = false;
state.data = [];
do {
async function myFetch() {
let url = `https://api.github.com/users/${userName.value}/repos?per_page=5`;
let response = await fetch(url);
if (!response.ok) {
success.value = false;
throw new Error(`HTTP error! status: ${response.status}`);
}
success.value = true;
// check response.headers for Link to get next page url
split1.spl1 = response.headers.get("Link").split(",");
let j = 0;
while (j < split1.spl1.length) {
split2.spl2[j] = split1.spl1[j].split(";");
console.log(split2.spl2[j][0]);
console.log(split2.spl2[j][1]);
if (split2.spl2[j][1].includes("next")) {
let urlNext = split2.spl2[j][0].replace(/[<>(\s)*]/g, "");
console.log(urlNext);
url = urlNext;
hasNext = true;
break;
} else {
hasNext = false;
}
j++;
}
// second .then
let myData = await response.json();
state.data.push(...myData);
console.log("data", myData);
name.value = "";
}
myFetch().catch((err) => {
if (err.status == 404) {
console.log("User not found");
} else {
console.log(err.message);
console.log("oh no (internet probably)!");
}
});
} while (hasNext);
});
// Sort list by star count
const orderedList = computed(() => {
if (state.data == 0) {
return [];
}
return [...state.data].sort((a, b) => {
return a.stargazers_count < b.stargazers_count ? 1 : -1;
});
});
return {
myFetch,
success,
isActive: true,
name,
userName,
ListElement,
...toRefs(state),
orderedList,
};
},
};
Any help would be highly appreciated
The call to myFetch() near the end is a call to an async function without an await, so it is effectively going to loop (if hasNext was initialized to true, but it isn't) without waiting for it to complete.
You should probably change that line to await myFetch() and wrap it all with a try/catch block.
I also don't really care for the way you're directly updating state inside the async myFetch call (it could also be doing several of those if it looped) and perhaps it should be returning the data from myFetch instead, and then you can use let result = await myFetch() and then make use of that when it returns.
Also, instead of awaiting myFetch() result, you could not await it but push it onto a requests array and then use await Promise.all(requests) outside the loop and it is one operation to await, all requests running in parallel. In fact, it should probably be await Promise.allSettled(requests) in case one of them fails. See allSettled for more.
But also I wonder why you're reading it paged if the goal is to fetch them all anyway? To reduce load on the server? If that is true, issuing them paged but in parallel would probably increase the load since it will still read and return all the data but require multiple calls.
I am building an application using vue 2.6.11 and vuex 3.6.0
The page I am building is for an event registration. The ActiveEvent is fetched from the database (Event ID, Date, Location etc) using an API
The registration form first asks for an email address. On blur of the email field we then fire the checkEmail(). This should do one or two API calls. The first call checks to see if we have the email address in the database and returns the ParticipantID, and if we do then a second call is made to see if the participant is already registered against this event using Event.EventID and ActiveUser.ParticipantID
The stucture of the page being loaded is a page component <EventDetail> called from the router. This has a main component <EventRegistration> which calls two separate sub-components: <EventRegistrationBlurb> which gets the state.ActiveEvent passed as a prop and <EventRegistrationForm> which is fetching the state.ActiveEvent directly. The outer component <EventRegistration> is responsible for fetching the Event data from the API and setting state.ActiveEvent which is does successfully,
What I am failing to understand is why when I call checkEmail in my component, this.ActiveEvent is undefined. The puter component is fetching the API and setting the state correctly as the blurb component is correctly rendering it. If I put the ActiveEvent object into the template for the EventRegistrationForm it renders correctly, it is just not being set in time for the binding to be made to the method checkEmail()
I have the following code in my sub-component <EventRegistrationForm>: (NOTE, ActiveEvent is set by an outer component and does get set correctly)
methods: {
...mapActions(['CheckParticipantByEmail']),
async checkEmail () {
const payload = {
email: this.form.email,
EventID: this.ActiveEvent.EventID // <-- THIS IS UNDEFINED???
}
await this.CheckParticipantByEmail(payload)
}
},
computed: {
...mapState(['ActiveEvent', 'ActiveUser'])
}
and then in my store:
state: {
ActiveEvent: {},
ActiveUser: {}
},
mutations: {
SET_ACTIVE_EVENT (state, payload) {
state.ActiveEvent = payload
},
CHECK_PARTICIPANT_BY_EMAIL (state, payload) {
state.ActiveUser = payload
},
GET_PARTICIPANT_FOR_EVENT (state, payload) {
state.ActiveUser = payload
}
},
actions: {
async CheckParticipantByEmail ({ commit }, payload) {
console.log('payload', payload)
const baseUrl = process.env.VUE_APP_API_URL
const url = `${baseUrl}getParticipantbyEmail`
const { email, EventID } = payload
const response = await axios.post(
url,
{
EmailAddress: email
}
)
const User = await response.data[0]
commit('CHECK_PARTICIPANT_BY_EMAIL', User)
if (User.ParticipantID > 0) {
const baseUrl = process.env.VUE_APP_API_URL
const url2 = `${baseUrl}getParticipantForEvent`
const payload2 = {
ParticipantID: User.ParticipantID,
EventID: EventID
}
alert('URL2: ' + url2)
alert('payload2 participant: ' + payload2.ParticipantID)
alert('payload2 event: ' + payload2.EventID)
const response2 = await axios.post(
url2,
payload2
)
// console.log('response: ', response.data[0])
const payload3 = response2.data[0]
commit('GET_PARTICIPANT_FOR_EVENT', payload3)
}
}
}
As usual, it turns out to be an interface error between the chair and the keyboard. This page is normally accessed from a list of events which is an array of objects where the identifier is EventID. When calling the separate events the identifier is just ID so the code in the payload2 should read
const payload2 = {
ParticipantID: User.ParticipantID,
EventID: ID // <- NOTE change of identifier.
}
I think I will update the API to return a consistent identifier and avoid the headache later on. Only wasted about 3 hours on this...
My problem is that when I go from one user page to another user page the info in component still remains from first user. So if I go from /user/username1 to /user/username2 info remains from username1. How can I fix this ? This is my code:
UserProfile.vue
mounted() {
this.$store.dispatch('getUserProfile').then(data => {
if(data.success = true) {
this.username = data.user.username;
this.positive = data.user.positiverep;
this.negative = data.user.negativerep;
this.createdAt = data.user.createdAt;
this.lastLogin = data.user.lastLogin;
data.invites.forEach(element => {
this.invites.push(element);
});
}
});
},
And this is from actions.js file to get user:
const getUserProfile = async ({
commit
}) => {
try {
const response = await API.get('/user/' + router.currentRoute.params.username);
if (response.status === 200 && response.data.user) {
const data = {
success: true,
user: response.data.user,
invites: response.data.invites
}
return data;
} else {
return console.log('Something went wrong.');
}
} catch (error) {
console.log(error);
}
};
Should I add watch maybe instead of mounted to keep track of username change in url ?
You can use watch with the immediate property, you can then remove the code in mounted as the watch handler will be called instead.
watch: {
'$route.params.username': {
handler: function() {
this.$store.dispatch('getUserProfile').then(data => {
if(data.success = true) {
this.username = data.user.username;
this.positive = data.user.positiverep;
this.negative = data.user.negativerep;
this.createdAt = data.user.createdAt;
this.lastLogin = data.user.lastLogin;
data.invites.forEach(element => {
this.invites.push(element);
});
}
});
},
deep: true,
immediate: true,
},
}
Your page is loaded before the data is retrieved it seems, you need put a "loading" property in the data and have a v-if="!loading" for your component then it will only render once the display is updated. Personally I would avoid watch if I can it is not great for performance of for fine grained handling.
Yes you should add wach on statement that contain user info.(you may have a problem to watch on object, so you can save user info in json, but im not sure). When user changing - call action, after recived response call mutation that should change a state, then watch this state.
And you might use better syntax to receive data from store. That is really bad idea call dispatch directly from your mouted hook, use vuex documentation to make your code better.
I have a list of companies in React Native.
When I click on one of those companies I get the url of the API that is used for selected company. Then I store it to AsyncStorage and then I show the login screen. The function is as follows:
selectCompany(data_url, e) {
AsyncStorage.setItem("data_url", JSON.stringify(data_url), () => this.props.login());
}
Then on login page if I click on sign in button I go to the onLogin function, the function is as follows:
onLogin: function() {
fetch(data.url + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
},
And data.url comes from data.js file, and I try to get url from the data.js file as follows:
let data_url = AsyncStorage.getItem("data_url").then(json => JSON.parse(json));
module.exports = {
url: data_url,
.....
}
But it doesn't work. Any advice?
AsyncStorage is async, therefore data_url will not be defined until it's retrieved what its looking for, you would need to move the fetch into the promise thats returned from the get so it will run it once it's done getting the data. This might be one way you tackle it:
const data_url = () => AsyncStorage.getItem("data_url"); //change this into a function
module.exports = {
url: data_url,
.....
}
now inside your component...
onLogin: function() {
data.url().then((url) => {
fetch(JSON.parse(url) + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
});
},
AsyncStorage.getItem is a promise and needs to await for response rather than accessing direct and the function calling it should be defined as async. Here is an example to retrieve from AsyncStorage..
export async function getAccessKey(){
let accessToken = await AsyncStorage.getItem(ACCESS_TOKEN);
return accessToken;
}
consider the following snippet.how can i access the value of the page url outside the page context?globally accessing the value was not working either.callbacks wasn't clear to me in approach.
page.onUrlChanged = function(targetUrl) {
console.log('New URL: ' + targetUrl);
};
page.onConsoleMessage = function (msg) {
console.log(msg);
};
var abc=page.open(url,function(status){
page.evaluate(function(){
//some code;
})
return page.url;
});
console.log(abc);
the code always gives undefined page url.
PhantomJS documents are very much recommended: http://phantomjs.org/api/webpage/method/evaluate.html
page.open(url,function(status){
var current_url = page.evaluate(function(){
return document.location.href;
})
console.log(current_url);
});