MeteorJS project with redis-livedata package not returning object from redisCollection.hgetall as expected - meteor

The MeteorJS method "get.jade" is not returning jade object to client as expected. I'm using redis-livedata and manuel:reactivearray packages, and Redis is functioning locally correctly. I have put console.log in the code where there is a problem is returning server side data to client
jades.html
<template name="jades">
{{#if jadeslength}}
<div class="row">
<div class="user-card" id="swipe">
<img src="{{jade.img}}" style="width:100%">
<div class="card-container">
<h5>{{jade.name}}, {{jade.gender}}</h5>
</div>
</div>
</div>
<div class="row">
<div class="one-half column">
<button class="no" type="button">no</button>
</div>
<div class="one-half column">
<button class="button-primary yes" type="button">yes</button>
</div>
</div>
{{else}}
<div class="row">
<button class="button-primary search-jades" type="button" id="search">search</button>
</div>
{{/if}}
</template>
jades.js
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import './jades.html';
Template.jades.onCreated(function () {
var jades = new ReactiveArray([]);
Session.set({'jadeId':""});
});
Template.jades.helpers({
jade: function() {
return jades.list();
},
jadeslength: function() {
var jades = jades.list();
return jades.length;
},
});
Template.jades.events({
...
'click .search-jades' () {
Template.instance.jades = [];
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var client_location = {"lat": position.coords.latitude, "lng": position.coords.longitude};
if (client_location) {
var lng = client_location.lng;
var lat = client_location.lat;
Meteor.call('client.profile', (error, result) => {
if (error) {
FlashMessages.sendError(error, 3000);
} else {
var user_profile = result;
Session.set({'user_profile': user_profile});
var prefer = user_profile.prefer;
switch (prefer) {
case "cis women":
Meteor.call('search.cw', lng, lat, (error, result) => {
if (error) {
FlashMessages.sendError(error, 3000);
return;
} else {
searched = result;
if (searched.length == 0) {
FlashMessages.sendWarning("no more providers found in your area", 3000);
} else {
for (var found of searched) {
var user_profile = Session.get('user_profile');
var right = user_profile.right;
if (!(found._id in right)) {
Template.instance.jades.push(found._id);
}
}
var jadeId = Template.instance.jades.pop();
console.log(jadeId); // returns ofQj98LBQWrSJ8gJs on client
if (jadeId) {
Meteor.call('get.jade', jadeId, (error, result) => {
if (error) {
FlashMessages.sendError(error, 3000);
} else {
Session.set({'jadeId': jadeId});
Session.set({'jade': result});
console.log(result); // returns undefined on client
}
});
} else {
FlashMessages.sendWarning("no more providers found in your area", 3000);
}
}
}
});
break;
case "trans women":
...
methods.js
'get.jade': function(jadeId) {
var redisCollection = new Meteor.RedisCollection("redis");
redisCollection.hgetall(jadeId, function(error, object) {
if (error) {
console.log(error);
} else {
console.log(object); // returns { name: 'alex', img: 'null', gender: 'cis woman' } on server
return object;
}
});
},

I solved this by changing the method as follows:
'get.jade': function(jadeId) {
var redisCollection = new Meteor.RedisCollection("redis");
return redisCollection.hgetall(jadeId)
},

Related

DropdownList Doesn't Work on Mobile Devices

I have 2 dropdown list in my page. In web browser (PC side) It works fine. There is no problem. When i open the page with chrome toogle device toolbar and i resize as mobile view, it only gives this error
fastclick.js:1 [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
csHTML Code
<div class="tab-pane active tabcontent" id="reservationPage" role="tabpanel">
<div class="col-sm-12 col-md-12">
<div class="form-group row rowR">
<label class="form-control-label col-md-2"><strong>Yemekhane</strong> </label>
<div class="col-md-12">
#Html.DropDownListFor(x => x.RefectoryId, new SelectList(Model.Refectories, "Id", "Name"), ("Seçiniz"), new { Id = "RefectoryId", #class = "form-control select2" })
</div>
</div>
<div class="form-group row rowR">
<label class="form-control-label col-md-2"><strong>Öğün</strong> </label>
<div class="col-md-12">
#Html.DropDownListFor(x => x.FoodMealId, new SelectList(Model.FoodMeals, "Id", "Name"), ("Seçiniz"), new { Id = "FoodMealId", #class = "form-control select2" })
</div>
</div>
</div>
</div>
JS Code
<script>
var reservationCount = 0;
var totalAmount = 0;
$(document).ready(function () {
$("#reservationCount")[0].textContent = "(" + reservationCount + ")";
//İlk açıldığında rezervasyon sayfasının acık gelmesi için
var tablinks = document.getElementById("reservationPageHead");
tablinks.className = tablinks.className + " active";
document.getElementById('reservationPage').style.display = "block";
//var foodMealId = $("#FoodMealId").val();
//var refectoryId = $("#RefectoryId").val();
//GetCalendarMenuPartial(foodMealId, refectoryId);
$("#RefectoryId").select2({
allowClear: true,
placeholder: 'Yemekhane Seçiniz',
// dropdownParent: $(".bootbox-body"),
});
var refectorySelect = $('#RefectoryId');
refectorySelect.on("select2:select", function (e) {
var foodMealId = $("#FoodMealId").val();
var refectoryId = $("#RefectoryId").val();
$.ajax({
url: "#Url.Action("GetRefectoryWithFoodMeal", "Reservation", new { area = "Common" })",
data: { refectoryId: refectoryId },
type: "POST",
async: false,
success: function (returnData) {
if (returnData.data == undefined) {
PageToastr(returnData.type, returnData.message, returnData.title);
}
else {
//FoodMeal List
$("#FoodMealId option[value]").remove();
$("#FoodMealId").select2({
allowClear: true,
placeholder: 'Seçiniz',
data : returnData.data,
});
}
},
beforeSend: function () {
$(".loaderDiv").show();
$(".loader").show();
},
complete: function () {
$(".loaderDiv").hide();
$(".loader").hide();
},
error: function (xhr, status, err) {
if (xhr.status === 999) {
noAuthorize(this.url);
}
}
});
var foodMealId = $("#FoodMealId").val();
var refectoryId = $("#RefectoryId").val();
GetCalendarMenuPartial(foodMealId, refectoryId);
});
$("#FoodMealId").select2({
allowClear: true,
placeholder: 'Öğün Seçiniz',
//dropdownParent: $(".bootbox-body"),
});
var foodMealSelect = $('#FoodMealId');
foodMealSelect.on("select2:select", function (e) {
var foodMealId = $("#FoodMealId").val();
var refectoryId = $("#RefectoryId").val();
GetCalendarMenuPartial(foodMealId, refectoryId);
});
// Rezervasyonu tamamla için tooltip
$('#completeReservation').tooltip('update');
});
</script>
<script>
function GetCalendarMenuPartial(foodMealId, refectoryId) {
$.ajax({
url: '#Url.Action("NewReservationCalendarMenuPartial", "Reservation", new { area = "Common" })',
data: { foodMealId: foodMealId, refectoryId: refectoryId, addCardMenu: $("#AddCardMenuString").val() },
type: "POST",
success: function (partialPage) {
if (partialPage.title != undefined) {
PageToastr(partialPage.type, partialPage.message, partialPage.title);
if (partialPage.result == '#Enums.ResultStatus.SessionTimeExpired.ToString()') {
setTimeout(function () { window.location.href = '/Login/Login'; }, 5000)
}
}
else {
$("#calendarMenuPartial").html(partialPage);
}
},
beforeSend: function () {
$(".loaderDiv").show();
$(".loader").show();
},
complete: function () {
$(".loaderDiv").hide();
$(".loader").hide();
},
error: function (xhr, status, err) {
if (xhr.status === 999) {
noAuthorize(this.url);
}
}
});
}
</script>
After that I've added touch-action: none; but it doesn't work too. It works properly in PC Devices. But never works on mobile devices.

Two recaptcha controls, one of them is not working

I have two reCaptcha V2 controls within two forms in one page, one is visible another is invisible. All is fine except the invisible one's data-callback callback - submitSendForm() did not get called. Once I removed the visible one, the invisible one starts working.
So the process is like once user completed the first visible challenge then the second form(within same page) will show with the invisible one, that's when the call back failed to be called.
It hasn't to be one visible and another invisible. But I found this to be easy when you want to have multiple controls.
Here is the code:
using (Html.BeginForm("Verify", "CertificateValidation", FormMethod.Post, new { id = "verifyForm" }))
{
<div class="form-group">
<div class="g-recaptcha" data-sitekey='site-key' data-callback="enableBtn"
style="transform: scale(0.66); transform-origin: 0 0;">
</div>
<div class="col-sm-3">
<button type="submit" id="verify" disabled>Verify</button>
</div>
</div>
}
using (Html.BeginForm("Send", "CertificateValidation", FormMethod.Post, new { id = "sendForm" }))
{
<div id='recaptcha1' class="g-recaptcha"
data-sitekey='site-key'
data-callback="submitSendForm"
data-size="invisible"></div>
<button type="submit">Send</button>
}
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script type="text/javascript">
function submitSendForm() {
console.log('captcha completed.');
$('#sendForm').submit();
}
$('#sendForm').submit(function (event) {
console.log('form submitted.');
if (!grecaptcha.getResponse()) {
console.log('captcha not yet completed.');
event.preventDefault(); //prevent form submit
grecaptcha.execute();
} else {
console.log('form really submitted.');
}
});
var enableBtn = function (g_recaptcha_response) {
$('#verify').prop('disabled', false);
};
$(document).ready(function () {
$('#verify').click(function () {
$captcha = $('#recaptcha');
response = grecaptcha.getResponse();
if (response.length === 0) {
return false;
} else {
return true;
}
});
});
</script>
I got it figured out somehow:
var CaptchaCallback = function () {
grecaptcha.render('RecaptchaField1', { 'sitekey': 'site-key', 'callback': 'enableBtn' });
window.recaptchaField2Id = grecaptcha.render('RecaptchaField2', { 'sitekey': 'site-key', 'callback': 'submitSendForm', 'size': 'invisible' });
};
function submitSendForm() {
$('#sendForm').submit();
}
$('#sendForm').submit(function (event) {
if (!grecaptcha.getResponse(window.recaptchaField2Id)) {
event.preventDefault();
grecaptcha.execute(window.recaptchaField2Id);
}
});
using (Html.BeginForm("Verify", "CertificateValidation", FormMethod.Post, new { id = "verifyForm" }))
{
<div class="form-group">
<div style="transform: scale(0.66); transform-origin: 0 0;" id="RecaptchaField1"></div>
<div class="col-sm-3">
<button type="submit" id="verify" disabled>Verify</button>
</div>
</div>
}
using (Html.BeginForm("Send", "CertificateValidation", FormMethod.Post, new { id = "sendForm" }))
{
<div id="RecaptchaField2"></div>
<button type="submit">Send</button>
}
This one worked for me, clean and easy.
Javascript
var reCaptcha1;
var reCaptcha2;
function LoadCaptcha() {
reCaptcha1 = grecaptcha.render('Element_ID1', {
'sitekey': 'your_site_key'
});
reCaptcha2 = grecaptcha.render('Element_ID2', {
'sitekey': 'your_site_key'
});
};
function CheckCaptcha1() {
var response = grecaptcha.getResponse(reCaptcha1);
if (response.length == 0) {
return false; //visitor didn't do the check
};
};
function CheckCaptcha2() {
var response = grecaptcha.getResponse(reCaptcha2);
if (response.length == 0) {
return false; //visitor didn't do the check
};
};
HTML
<head>
<script src="https://www.google.com/recaptcha/api.js?onload=LoadCaptcha&render=explicit" async defer></script>
</head>
<body>
<div id="Element_ID1"></div>
<div id="Element_ID1"></div>
</body>

Meteor: How can I restrict user on a chat?

Im working on a project and my last task is to implement publish and subscribe to prevent users seeing conversations they were not involved in. We were given an example code and I notice a filter on the router.
Router.route('/chat/:_id', function () {
// the user they want to chat to has id equal to
// the id sent in after /chat/...
var otherUserId = this.params._id;
// find a chat that has two users that match current user id
// and the requested user id
var filter = {$or:[
{user1Id:Meteor.userId(), user2Id:otherUserId},
{user2Id:Meteor.userId(), user1Id:otherUserId}
]};
var chat = Chats.findOne(filter);
if (!chat){// no chat matching the filter - need to insert a new one
chatId = Chats.insert({user1Id:Meteor.userId(), user2Id:otherUserId});
}
else {// there is a chat going already - use that.
chatId = chat._id;
}
if (chatId){// looking good, save the id to the session
Session.set("chatId",chatId);
}
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
I thought the filter should be on publish and then subscribe. Here is what I have now.
My HTML
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each recentMessages}}
{{> message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
{{#if currentUser}}
<form class="new-message">
<input class="input" type="text" name="text" placeholder="type a message here...">
<button class="btn btn-default">Send</button>
</form>
{{/if}}
</div>
</div>
</template>
<!-- simple template that displays a message -->
<template name="message">
<div class = "container">
<div class = "row">
<div class = "username">
<img src="/{{avatar}}" class="avatar_img" >
{{username}}
said: {{messageText}}
</div>
</div>
</div>
</template>
Server Side
Meteor.startup(function () {
if (!Meteor.users.findOne()){
for (var i=1;i<9;i++){
var email = "user"+i+"#test.com";
var username = "user"+i;
var avatar = "ava"+i+".png"
console.log("creating a user with password 'test123' and username/ email: "
+ email);
Meteor.users.insert({
profile:{username:username, avatar:avatar},
emails: [{address:email}],
services:{
password:{"bcrypt" : "PASSWORD REMOVED"}}});
}
}
});
Meteor.publish("messages", function (userId) {
return Messages.find();
});
Meteor.publish("userStatus", function() {
return Meteor.users.find({ "status.online": true });
});
Meteor.publish("userData", function(){
if(this.userId) {
return Meteor.users.find({_id: this.userId},{
fields: {'other':1, 'things': 1}});
} else {
this.ready();
}
return Meteor.users.find({ "status.online": true })
});
Client Side
Meteor.subscribe("messages");
Meteor.subscribe("userStatus");
Meteor.subscribe("userData");
// set up the main template the the router will use to build pages
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
// specify the top level route, the page users see when they arrive at the site
Router.route('/', function () {
console.log("rendering root /");
this.render("navbar", {to:"header"});
this.render("lobby_page", {to:"main"});
});
Router.route('/chat/:_id', function () {
this.render("navbar", {to:"header"});
this.render("chat_page", {to:"main"});
});
///
// helper functions
///
Template.message.helpers({
userName: function() {
var userId = this.userId;
var user = Meteor.users.findOne(userId);
var username = user && user.profile && user.profile.username;
var avatar = user && user.profile && user.profile.avatar;
return {
username: username,
avatar: avatar
}
}
})
Template.available_user_list.helpers({
users:function(){
return Meteor.users.find();
}
})
Template.available_user.helpers({
getUsername:function(userId){
user = Meteor.users.findOne({_id:userId});
return user.profile.username;
},
isMyUser:function(userId){
if (userId == Meteor.userId()){
return true;
}
else {
return false;
}
}
})
Template.chat_page.helpers({
recentMessages: function () {
if (Session.get("hideCompleted")) {
return Messages.find({checked: {$ne: true}}, {sort: {createdAt: -1}});
} else {
return Messages.find({}, {sort: {createdAt: 1}});
}
},
hideCompleted: function () {
return Session.get("hideCompleted");
},
incompleteCount: function () {
return Tasks.find({checked: {$ne: true}}).count();
}
});
Template.chat_page.events({
// this event fires when the user sends a message on the chat page
'submit .new-message':function(event){
console.log(event);
event.preventDefault();
var text = event.target.text.value;
// stop the form from triggering a page reload
event.target.text.value = "";
// see if we can find a chat object in the database
// to which we'll add the message
Meteor.call("sendMessage", text);
},
});
Collections
Messages = new Mongo.Collection("messages");
Shared-Methods
Meteor.methods({
sendMessage: function (messageText) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Messages.insert({
messageText: messageText,
createdAt: new Date(),
username: Meteor.user().profile.username,
avatar: Meteor.user().profile.avatar,
});
}
});

YouTube API loadVideoById startSeconds not working

I created a chapter selector for some youtube videos I was embedding. This method used to work but has stopped recently. I can't figure out what's going on.
I'm using their recommended format but use loadVideoById to show each chapter
<div class="wrapper">
<div id="player"></div>
<script type="text/javascript">
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
width: '625',
videoId: 'FE5jN0rqMtM',
events: {
'onStateChange': onPlayerStateChange
},
playerVars:{
rel: 0,
wmode: "opaque"
}
});
}
function onPlayerStateChange(evt) {
if (evt.data == 0) {
$('#video_popup').removeClass('hide_pop');
$('#video_popup').addClass('display_pop');
}
else if (evt.data == -1) {
$('#video_popup').removeClass('display_pop');
$('#video_popup').addClass('hide_pop');
}
else {
$('#video_popup').removeClass('display_pop');
$('#video_popup').addClass('hide_pop');
}
}
function chapter1() {
player.loadVideoById({'videoId': 'FE5jN0rqMtM', 'startSeconds': 0});
}
function chapter2() {
player.loadVideoById({'videoId': 'FE5jN0rqMtM', 'startSeconds': 63});
}
function chapter3() {
player.loadVideoById({'videoId': 'FE5jN0rqMtM', 'startSeconds': 135});
}
</script>
<div id="video_popup" class="hide_pop">
<div class="video_layover">
<div class="promo">Thank you for watching!<br /><br /></div>
<div class="link">Replay Video</div>
</div>
</div>
<div style="margin: 0 auto 20px auto; width:625px; height:98px; text-align:center;">
<ul class="player">
<li>Chapter 1</li>
<li>Chapter 2</li>
<li>Chapter 3</li>
</ul>
</div>
I'm guessing it is a bug though I wasn't able to find it documented. You could report the bug if you want.
Regardless, I think cueVideoById is a better method which is working for me in all browsers:
Example: JS Bin
function chapter2() {
player.cueVideoById('FE5jN0rqMtM', 63); // BETTER WAY
player.playVideo();
}
If you experienced an error like "TypeError: ytPlayer.loadVideoById is not a function",
then I believe you have to wait for the onReady event to fire.
Here is the sample code (part of) I use:
var ytPlayer;
var ytPlayerIsReady = false;
// this methods only works if defined in the global scope !!
window.onYouTubeIframeAPIReady = function () {
ytPlayer = new YT.Player('ytplayer', {
playerVars: {
enablejsapi: 1,
controls: 0,
fs: 1,
autoplay: 1,
rel: 0,
showinfo: 0,
modestbranding: 1
},
events: {
onReady: onReady,
onError: onError,
onStateChange: onStateChange
}
});
};
// youtube code for calling the iframe api
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onError(event) {
console.log("error with code" + event.data);
}
function onStateChange(event) {
console.log("change state to " + event.data);
}
function onReady(event) {
ytPlayerIsReady = true;
console.log("I'm ready");
}
window.myVideoPlayer = {
init: function (options) {
// some arbitrary code...
// the trick is to fire options.callback,
// which contains all the logic needed
function timeout() {
setTimeout(function () {
if (false === ytPlayerIsReady) {
timeout();
}
else {
if (options.callback) {
options.callback();
}
}
}, 1000);
}
timeout();
}
};
myVideoPlayer.init({
callback: function(){
// now the youtube api is ready, you should be able to call
// loadVideoById without problems (at least it worked for me)
// ytPlayer.removeEventListener('onStateChange');
// ytPlayer.addEventListener('onStateChange', '_myYtPlayerOnChange');
// ytPlayer.loadVideoById({
// videoId: 'xxxx',
// startSeconds: 12
// });
}
});
You need to make sure var player is ready before calling loadVideoById
If(player != null)
{
loadVideoById ..
}

Log in/out button no longer maintaining state

My code was working fine until the past 24 hours. I did not change anything, but now the #fb-button is smaller and it no longer says "Log Out" when it should.
You can see this in action at Homewrd.
The following code is nested in BODY > ROOT:
<div id="fb-root"></div>
<script type="text/javascript">
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Init the SDK upon load
window.fbAsyncInit = function() {
FB.init({
appId:'271193286279763',
channelUrl:'//'+window.location.hostname+'/channel',
status:true,
cookie:true,
xfbml:true
});
// Conditional UI for landing page
if (landing) {
FB.getLoginStatus(function(response) {
if(response && response.status == 'connected') {
FB.api('/me', function(response) {
var heading = $('#goods h1').text().replace('Homewrd','Welcome '+response.first_name+'!');
$('#goods h1').text(heading);
});
}
});
}
// listen for and handle auth.statusChange events
FB.Event.subscribe('auth.statusChange', function(response) {
fbEventful = true;
if (response.authResponse) {
fbToken = response.authResponse.accessToken;
$('#fb-button').css({'display':'inline','float':'left'});
$('#toolbox').css({'display':'inline'});
$('#local-login').hide();
$('#local-logout').hide();
currentUser = {
fbid:response.authResponse.userID
}
displayPicture();
} else {
$.cookie('cuat', null);
$.ajax({
url:'/logout.json',
type:'delete',
success:function() {
ajaxOff();
renderLocal();
}
});
}
});
FB.Event.subscribe('auth.login',
function(response) {
FB.api('/me', function(me){
if (me.name) {
currentUser = {
fbid:me.id,
email:me.email,
first_name:me.first_name,
last_name:me.last_name
}
params = {
fbid: currentUser.fbid,
user: {
fbid:currentUser.fbid,
email:currentUser.email,
first_name:currentUser.first_name,
last_name:currentUser.last_name
}
}
$.ajax({
url:domain+'/user.json',
data:params,
dataType:'json',
type:'post',
success:function(e) {
cuat = e.user.auth_token;
$.cookie('cuat', cuat, {
path:'/',
expires:7
}
);
if (rurl) {
refreshSession();
}
if (storedProcedure!==null) {
storedProcedure();
}
}
});
}
});
}
);
$('#local-logout a').click(function(e) {
e.preventDefault();
var x = confirm('Are you sure that you want to logout?');
if (x===true) {
ajaxOn();
$.ajax({
url:'/logout.json',
type:'delete',
success:function() {
ajaxOff();
window.location.reload();
}
});
}
return false;
});
setTimeout(function() {
if (!fbEventful) {
renderLocal();
}
},1000);
}
</script>
<div id="header">
<div id="logo">
<h1>Logo Link</h1>
</div>
<div id="session">
<div id="fb-button" autologoutlink="true" class="fb-login-button" scope="publish_stream,email,user_about_me,user_birthday,user_hometown,offline_access"></div>
<div id="fb-picture"></div>
<div id="local-login"><p>local login link</p></div>
<div id="local-logout"><p>local logout link</p></div>
</div>
</div>

Resources