[EDIT] i'm using Meteor
Hi everyone,
i've searched and tried many things but i can't do what i want.
I'm doing a tutorial to do a ToDo list, and when u check a task, i want to put the name of the user who checked the task.
<template name="task">
<li class="{{#if checked}}checked{{/if}}">{{#if checked}}<!-- the name of the user who checked it -->{{/if}}
<!-- the rest isn't useful for my question -->
I've tried with {{currentUser.username}} but when i log with someone else the name change...
There is the JS for the event handler
'click .toggle-checked'() {
// Set the checked property to the opposite of its current value
Meteor.call('tasks.setChecked', this._id, !this.checked);
}
And the JS for the method call
'tasks.setChecked'(taskId, setChecked) {
check(taskId, String);
check(setChecked, Boolean);
Tasks.update(taskId, { $set: { checked: setChecked } });
}
Thank you for the help
If you use {{currentUser.username}} you will always have the data of the logged in user.
To get what you want you need to register the _id of the user who checked the task in your method:
'tasks.setChecked'(taskId, setChecked) {
check(taskId, String);
check(setChecked, Boolean);
// Check that 'setChecked' is true and that the user is logged in,
// Otherwise just update the status
if (setChecked && this.userId) {
Tasks.update(taskId, {
$set: {
checked: setChecked,
userId: this.userId,
}
});
} else {
Tasks.update(taskId, {
$set: {
checked: setChecked,
}
});
}
}
Make sure you update your schema accordingly if you are using one.
Then in your template, retrieve the user data and display it:
// file task.js
import './task.html';
Template.task.helpers({
checkerUser() {
// The template data are those of the current task, check if userId is defined and task is checked
const { userId, checked } = Template.currentData();
/* Or you can do
* const userId = Template.currentData().userId;
* checked = Template.currentData().checked;
*/
if (userId && checked) {
return Meteor.users.findOne({ _id: userId }).profile.username;
}
return null;
}
});
Template.task.events({
'click .toggle-checked'() {
// Set the checked property to the opposite of its current value
Meteor.call('tasks.setChecked', this._id, !this.checked);
}
})
And finally in HTML:
// file task.html
<template name="task">
<li class="{{#if checked}}checked{{/if}}">
{{#if checkerUser}}Completed by {{checkerUser}}{{/if}}
</li>
</template>
Technically, in your method you should also check more in-dept the different situations. For instance, when you uncheck a task, it should remove the userId from the record so that if a non logged-in user checks it again, the name won't be the one of the first user (or you could $unset userId if user is not logged in when setting checked = true)
Related
Is it possible to delete session[:sth] using jQuery/Javascript ?
In the Rails controller I set the session parameters:
def new
#other logic (...)
session[:patient_id_to_add_caregiver] = params[:patient_to_caregiver]
end
Below I've got simple function to handle case when the user selects one field from dropdown list, search field and search results should be hidden:
registrants.js
function toggle_caregiver_fields_on_ready(){
var caregiverSectionElement = $("#registrant_registration_attributes_registrant_id");
if ($("#registrant_registration_attributes_registered_as").val() === 'caregiver') {
$('.patient-caregiver-section').removeClass('hidden');
$('#patient-search-results').removeClass('hidden');
} else {
$('.patient-caregiver-section').addClass('hidden');
$('#patient-search-results').addClass('hidden');
}
}
In the same JS function I want to clear session[:patient_id_to_add_caregiver] when (#registrant_registration_attributes_registered_as").val() === 'caregiver'). I've tried with sessionStorage.clear(); to be:
if ($("#registrant_registration_attributes_registered_as").val() === 'caregiver') {
sessionStorage.clear();
$('.patient-caregiver-section').removeClass('hidden');
(...)
But nothing happened. Is it possible to clear this session storage?
I am bringing in data from an api call and outputting the data to html inside a template string using variables from the main.js file. All of that works fine. The problem that has me blocked is I want to have an add to favorites button that a user can click and add the title to a favorites list. When I add the button inside the template literal the addEvenListener I have for the button is null and if I add the button to the index.html I cannot access the data from the api. I am trying to store the data first into firestore database after the user clicks the button. Then output the data into a dropdown list.
I've added a collection to the firestore database and can display the data from the backend to the favorites list but I need to grab the data from the front end, store it on the back end, and display it in the favorites list.
function getMovie(){
let movieId = sessionStorage.getItem('movieId');
// Make a request for a user with a given ID
axios.get("https://api.themoviedb.org/3/movie/" + movieId + "?
api_key=redacted")
.then(function (response) {
console.log(response)
let movie = response.data;
//console.log(movie);
let output = `
<div class="dropdown">
<button class="dropbtn" id="dropbtn">Favorites</button>
<div id="myDropDown" class="dropdown-content"></div>
</div>
`;
$('#movie').html(output);
})
.catch(function (error) {
console.log(error);
});
}
addFavorite.addEventListener('submit', (e) => {
e.preventDefault();
firebase.firestore().collection('favorites').add({
Title: addFavorite['movieid'].value
}).then(() => {
//close
console.log(addFavorite)
})
})
Not sure if I need to do another api call for this functionality or not. I did one api call to get a list of movies then another to get one movie. When the user goes to the one movie that is where I want the add favorite button. I hope someone knows how to lead me in the right direction. First time asking on Stackoverflow don't hurt me lol
i am taking simple ul list as example
<ul id="movie">
</ul>
<script>
// DUMMY records
const apiCallDataExample = [
{
id: 1,
name: "A"
},
{
id: 2,
name: "B"
},
{
id: 3,
name: "C"
}
];
let movies = [];
getMovie();
function getMovie() {
movies = apiCallDataExample; // You will call your API to get the data, and store it in upper scope 'movies' variable.
let htmlContent = ''; // prepare your html content -> in your case it is droup down i guess.
for (let movie of movies) {
htmlContent += `
<li>
<span> ${movie.name} </span>
<button onclick="addToFavourite(${movie.id})"> click me </button>
</li>
`
// Attach click event or any listener to get selected movie id or any identifier
}
let elem = document.getElementById("movie").innerHTML = htmlContent;
}
/**
* click event will trigger and we can fetch selected movie by given identifier, in my case it is `id `field.
*/
function addToFavourite(id) {
let selected_movie = movies.find(movie => movie.id === id); // find your movie by id.
console.log("selected movie is", selected_movie)
// add your data into collection as per your defined property , my case { id, name}.
/*
// Your fire base function
firebase.firestore().collection('favorites').add({
id: selected_movie.id,
name: selected_movie.name
}).then(() => { })
*/
}
</script>
I have list of product , If I click on one product it needs to be added in database and again if I click on same product it should be removed from database, I am toggling wishlistFlag on ng-click. It should be fine on one div element, for second div element it is working reverse of first div element, I mean in case first product is added then if I click second product it has to be added but it is removing first product.
<div class="hmpal-prprt-post-wdgt hmpal-prprt-wishlist">
<a href="">
<span class="prprt-icon"><i class="fa fa-heart" aria-hidden="true"
ng-click="WishlistAdd($index,project.propertyId)"></i></span>
<span>Wishlist</span>
</a>
</div>
And inside Controller code is here,
a.WishlistAdd = function (index,propertyId) {
a.wishlistFlag = !a.wishlistFlag;
var data = {
wishlistFlag:a.wishlistFlag,
propertyId:propertyId
};
e.createWishLists(data).then(function (result) {
alert("sucesss");
alert(JSON.stringify(result));
}, function (error) {
alert("error");
alert(JSON.stringify(error));
});
}
How I can implement toggle wishlistFlag for different product .
Since you want at most one product selected in your wish list, instead of having a boolean flag, you can use the selected product id (called propertyId in your code if I'm right). The selectedProductId variable, defined in the controller, is either null if there is no product selected, or the product id if there is one.
The toggling is done by checking if the current selected id is equal to the clicked one.
I assume that
when wishListFlag === true in the sent data, you want to add the
product identified by propertyId, and otherwise, remove the
product from the database.
when you add a product, the server side
actually replace the selected product if there is an existing one.
// Is there a selected product ?
var selectedProductId = null;
a.WishlistAdd = function (index, propertyId) {
selectedProductId = (selectedProductId === propertyId ? null : propertyId);
var data = {
wishlistFlag: (selectedProductId !== null),
propertyId: propertyId
};
e.createWishLists(data).then(function (result) {
alert("sucesss");
alert(JSON.stringify(result));
}, function (error) {
alert("error");
alert(JSON.stringify(error));
});
}
You can make use of $index to have seperate flag to each of the wishList. Here, you can write your code as..
a.wishListFlag[index]
maintain a array of added propertyIds before save to the database check that id is in array if so remove from database and array else remove from database and array.
var wishList = [];
a.WishlistAdd = function (index,propertyId) {
var data = {
wishlistFlag: wishList.indexOf(propertyId) === -1,
propertyId:propertyId
};
e.createWishLists(data).then(function (result) {
//add or remove propertyid from whishList
if(data.wishlistFlag)
wishList.push(propertyId);
else
wishList.splice(wishList.indexOf(propertyId), 1);
alert("sucesss");
alert(JSON.stringify(result));
}, function (error) {
alert("error");
alert(JSON.stringify(error));
});
}
I'm trying to insert the checkbox value (as boolean) into a subschema of my collection. Not clear on 1) how to pass the checkbox value (can do it for normal input field) and 2) how to insert into subschema. I am using collection2 and handlebars.
1-This is what I have in the HTML form that needs to be submitted:
`<div class="checkbox">
<label><input type="checkbox" id="byow" checked="{{isChecked}}" value="">Bring Your Own Wine</label></div>`
2-This is what I have in my helper (in controller) to get the value of the form and the checkbox value, submit it and call the method that inserts it into the collection:
`BackendController.events({
//Add Venue - Add New Venue Submit Form Helper
'submit #add-venue-form' : function(event) {
event.preventDefault();
var venueName = event.target.venueName.value;
var byow = event.target.byow.checked;
var params = {
venueName: venueName,
byow: byow
}
//Insert Venue
Meteor.call('addVenue', params);
toastr.success('VenueAdded');
Router.go('/admin/manage-venues')
}
3-This is my method that is called to insert into my Venues collection (first part) and the structure of my collection and sub-collection:
`Meteor.methods({
'addVenue': function (params) {
Venues.insert(params);
}
// MAIN SCHEMA for the Venues colleciton.
Schema.Venues = new SimpleSchema({
venueName: {
type: String,
label: "Venue Name",
max: 200,
optional: false
},
//Attach schema for venue attributes (cuisine type, amenities, etc)
venueAttributes: {
type: Schema.VenueAttributes,
optional: true
}
});
//schema for venue attributes. Attached to main schema
Schema.VenueAttributes = new SimpleSchema({
byow: {
type: Boolean,
optional: true
}
});
Would really appreciate any help - I've managed to get the venueName to be passed successfully (so all my permissions/pub/sub is correct) but stuck at checkbox and subcollection.
Thanks!
Dan.
Finally figured it out with the help of #lokenx on Meteor Chef Slack channel.
The checkbox code (first part) returned the correct value (true) when written as above.
My error was that I was not specifying byow as a subproperty (was treating it as root property of the simpleschema). The correct params I should have been passing are:
var params = {
venuaName: venueName,
venueAttributes: {
byow: byow
}
}
I would like to output data from two collections using a reactive join into my template, then pair the users, post and comments through a common id.
So far, I can see with Mongo commands that the JSON data exist, but my template doesn't render any data. What am I doing wrong?
FYI, the meteorpad doesn't compile but the github repo will.
Repo:
https://github.com/djfrsn/frontend-interview-test-long/tree/master/ontra/ontra
Meteor Pad Example:
http://meteorpad.com/pad/SvwkNrv5grgv2uXxH/Copy%20of%20Leaderboard
There's so much wrong that it's hard to know where to start.
1) When you're loading the initial post and user data you're inserting the whole returned array as one element rather than inserting each element individually into your posts collection.
2) You're creating a publish subscription with the name "postsSet", but you're trying to subscribe to it with a different name.
3) You're not calling publishComposite correctly at all. You should be publishing the user required for each post as part of the children array.
4) The template needs updating based on the above
5) The username needs to be supplied via a helper.
6) You should really map the "id" attributes to Mongo's "_id" instead.
Here's come code which works. Note that you'll need to call meteor reset everytime you restart, otherwise you'll get duplicate id errors since you currently reimport the data every time.
Posts = new Mongo.Collection("Posts");
var groundPosts = new Ground.Collection(Posts);
Users = new Mongo.Collection("Users");
var groundUsers = new Ground.Collection(Users);
if (Meteor.isClient) {
Meteor.subscribe("postsSet");
console.log('POSTS DATA = ' + Posts.find().fetch());
console.log('USERS DATA = ' + Users.find().fetch());
Template.body.events({
"submit .ontra": function (event) {
// This function is called when the new task form is submitted
var text = event.target.text.value;
Posts.insert({
content: text,
date: new Date() // current time
});
// Clear Form
event.target.text.value = "";
// Prevent default form submit
return false
}
});
Template.body.helpers({
posts: function() {
return Posts.find();
},
});
Template.post.helpers({
username: function() {
return Users.findOne({_id: this.userId}).username;
}
});
}
Meteor.methods({
'fetchJSONData': function() {
var postsResponse = Meteor.http.call("GET","https://raw.githubusercontent.com/djfrsn/frontend-interview-test-long/master/codetest/data/posts.json");
var usersResponse = Meteor.http.call("GET","https://raw.githubusercontent.com/djfrsn/frontend-interview-test-long/master/codetest/data/users.json");
var postsData = JSON.parse(postsResponse.content);
var usersData = JSON.parse(usersResponse.content);
postsData.forEach(function (post) {
post.date = new Date();
post._id = String(post.id)
delete post.id
post.userId = String(post.userId)
Posts.insert(post);
});
usersData.forEach(function (user) {
user.date = new Date() // current time
user._id = String(user.id)
delete user.id
Users.insert(user);
});
}
});
if (Meteor.isServer) {
Meteor.publishComposite('postsSet', {
find: function () {
return Posts.find({});
},
children: [
{
find: function (post) {
console.log("%j", post.userId);
console.log("%j", Users.findOne({ _id: post.userId }));
return Users.find({ _id: post.userId });
}
}
]
});
Meteor.call("fetchJSONData");
//console.log('POSTS DATA = %j', Posts.find().fetch());
//console.log('USERS DATA = %j', Users.find().fetch());
}
HTML:
<head>
<title>ontra</title>
</head>
<body>
<div class='container'>
<header>
<h1>ontra</h1>
<form class='ontra'>
<input type='text' name='text' placeholder="Type to add new post">
</form>
</header>
<ul>
{{#each posts}}
{{> post}}
{{/each}}
</ul>
</div>
</body>
<template name='post'>
<li>
<span class="text">{{content}}</span>
<span class="text">{{username}}</span>
</li>
</template>
Your code doesn't run on meteorpad because the fetchJSONData method is executed on the server before it is defined in the common.js file. You should probably be calling the method after an event triggered on the client, or not use a method at all and simply fetch your JSON data on Meteor.startup.
Regarding the reactive join, it seems you want to do something very similar to Example 1 of the documentation: https://github.com/englue/meteor-publish-composite