Meteor unique document field? - javascript

Im trying to build a learning app where at the moment it needs to get the first 7 posts from a subreddit and then if that is not already in the database add it to the database. However it runs both the if and else 7 times each for some reason and I cannot figure out why. Here is the helper method:
Template.posts.helpers({
posts : function () {
Meteor.call('getPosts', "tifu", function(e, results){
var result = JSON.parse(results.content).data.children;
Session.set('postsResults', result);
});
for(var i=0; i<7; i++){
var result = Session.get('postsResults')[i].data;
if(Posts.find({r_id: result.id}).count() == 0){
console.log("if");
} else {
console.log("else");
};
};
return Posts.find();
}
});
and the html side:
<template name="posts">
<div class="col-md-12 posts-div">
{{#each posts }}
<div class="col-md-8">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">{{ title }}</h3>
</div>
<div class="panel-body">{{{ body }}}</div>
<div class="panel-footer">
<div class="col-md-2">{{ score }}</div>
<div class="col-md-2 col-md-offset-3">{{ subreddit }}</div>
<div class="col-md-2 col-md-offset-3">{{ createdBy }}</div>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-primary">
</div>
</div>
{{/each}}
</div>
<hr>
</template>
I have replaced the insert code with simple console logs and these are the results I get:
if
if
if
if
if
if
if
else
else
else
else
else
else
else
When I run the Posts.find({r_id: result.id}).count() == 0 in the console I get false same with Posts.findOne({r_id: result.id}) == null but for some reason in javascript file it still runs the true portion and I then end up with like 50 copies of the same post which is what I am trying to avoid.

It is not optimal to use Meteor.call in a helper. The helper's function will re-run every time there is a reactive change. This is why it runs so many times.
Use the Template.onCreated callback instead:
Template.posts.onCreated(function() {
Meteor.call('getPosts', "tifu", function(e, results){
var result = JSON.parse(results.content).data.children;
Session.set('postsResults', result);
});
});
And your helper:
Template.posts.helpers({
posts : function () {
var r = Session.get('postsResults')
for(var i=0; i<7; i++){
if(!r) continue;
var result = r[i].data;
if(Posts.find({r_id: result.id}).count() == 0){
console.log("if");
} else {
console.log("else");
};
};
return Posts.find();
}
});
Second thing to keep in mind is Session.get('postsResults') will be null while the result of Meteor.call is returned, for a few hundred milliseconds. If you do Session.get('postsResults')[i].data you will get an exception.
This is why i added a conditional check to continue the loop if r is null. This way you wait for the result and the posts function will re-run and recalculate the results with the new data.

Related

Function Not Defined Error Inside HTML

I'm trying to get my facebook posts using the facebook graph api.But due to variation of likes,comment,share key in json data I had to make a function that could handle the cases.But when I'm trying to call the function in the html code below it shows function undefined errror.Can anyone please help me!!
function getPostsFacebookInfo(){
$.ajax('https://graph.facebook.com/me/posts?access_token='+myFacebookToken,{
success : function(response){
$.each(response.data,function(index,response){
console.log(response);
var react=function (){
if(response.hasOwnProperty('likes'))
{
$('#reactions').append(`<li class="list-group-item">Likes:${response.likes.data.length}</li>`);
}
else
{
$(' #reactions').append(`<li class="list-group-item">Likes:0</li>`);
}
if(response.hasOwnProperty('comments'))
{
$('#reactions').append(`<li class="list-group-item">Comments:${response.comments.data.length}</li>`);
}else
{
$('#reactions').append(`<li class="list-group-item">Comments:0</li>`);
}
if(response.hasOwnProperty('shares'))
{
$('#reactions').append(`<li class="list-group-item">Shares:${response.shares.data.length}</li>`);
}else
{
$('#reactions').append(`<li class="list-group-item">Shares:0</li>`);
}
};
$('#panelbody').append(`
<div class="well">
<div class="row">
<div class="col-md-9">
<p>${response.message}</p>
<img src="${response.picture}" class="img-thumbnail">
</div>
<div class="col-md-3" id="reactions">
<script>react();</script>//function call here..
</div>
</div>
</div>`);
//end argument list
});
}
});// end ajax call
}// end get facebook info
getBasicFacebookInfo();
getPostsFacebookInfo();

Ember components crashes on production

I'm having issues with my ember app when i build it on production, using ember serve all components work beautifully, but when I deploy it in my Digital Ocean droplet with Ubuntu 16.04 the app crashes with one component.
Here you had the code of the component that crashes:
import Ember from 'ember';
import pagedArray from 'ember-cli-pagination/computed/paged-array';
export default Ember.Component.extend({
init(){
this._super(...arguments);
this.send('fillQuestions');
},
didDestroyElement(){
this.send('reset');
},
last: false,
toggleModal: false,
aciertos: 0,
errores: 0,
contenido: Ember.computed('questions', function () {
let i = 0,
content = [],
contenido = [];
for (i; i < this.get('questions.length'); i++) {
content.push(this.get('questions.' + i + '.id_question_group.questions'));
}
contenido = [].concat.apply([], content);
return contenido;
}),
count: 0,
page: 1,
perPage: 1,
pagedContent: pagedArray('contenido', {
pageBinding: "page",
perPageBinding: "perPage"
}),
totalPagesBinding: "pagedContent.totalPages",
progressValue: 0,
color: Ember.computed('count', function () {
return new Ember.String.htmlSafe("width: " + this.get('progressValue') + "%;");
}),
actions: {
...(all my actions)
}
});
Inside my view I had this:
{{#if exam.show_progressbar}}
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow={{progressValue}} aria-valuemin="0" aria-valuemax="100" style={{color}}>
<span>{{progressValue}}%</span>
</div>
{{/if}}
{{#if exam.show_time}}
{{countdown-timer autoStart='false' startTime=exam.duration action='saveresponse'}}
{{/if}}
{{#each pagedContent as |result index|}}
<div class="text-center">
<p>{{result.questionID.description}}</p>
<br/><br/>
</div>
<form {{action 'saveresponse' on="submit"}}>
{{radio-group group=result.questionID.temp elements=result.questionID.rows action="updateValues" nombre=result.questionID.description}}
<br/>
<div class="row">
<div class="column text-left">
<button type="button" {{action 'showAlert'}} class="btn btn-primary">
Cancelar
</button>
</div>
</div>
{{#if last}}
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12 text-right">
<div class="column text-right">
<button type="submit" class="btn btn-primary">
Guardar examen
</button>
</div>
</div>
</div>
{{/if}}
</form>
{{/each}}
<div class="pager">
{{page-numbers content=pagedContent currentPage=page action='checkLast'}}
</div>
The error its in the next components: {{countdown-timer}} and {{radio-group}}
The countdown-timer is a component based on ember-cli-timer which counts from a set time to 0 and the radio-group component only had inside a radio-button helper.
Any ideas of why in production is not working and locally it's working?
UPDATE 03-23-2017
Using the chrome developer tools I've got this error, maybe this will explain a little more my problem.
Property set failed: You passed an empty path
UPDATE 04-24-2017
I just had found the exact error in the component, it's the next action:
actions: {
...
fillQuestions(){
let questions = this.get('contenido'); //Filled with exam questions
for(let i = 0; i < questions.length; i++){
if(questions[i].questionID !== null && questions[i].questionID !== undefined){
console.log(questions[i].questionID.description); //consoles the description of the question
this.set(questions[i].questionID.description, ''); //here it's the problem.
}
}
}
...
}
The line with this.set() its making the problem, and it's because questions[i].questionID.description it's the empty path it's there a way to create new properties in the component with an action of the same?
I finally found the error, the error was displayed when the component tried to set the new property.
The real problem was:
when I attempted to save the property of the question some questions got "." and it seems to be that Ember.computed does not allow to use them for a property, so when I tried this.set('some.question.with.dots', '') the error was triggered and display the Property set failed.
The solution was simple, I only had to use .replace() function of javascript to replace all the dots in the string.
The final code is next:
actions: {
...
fillQuestions(){
let questions = this.get('contenido'); //Filled with exam questions
for(let i = 0; i < questions.length; i++){
if(questions[i].questionID !== null && questions[i].questionID !== undefined){
let desc = questions[i].questionID.description.replace(/\./g,'');
this.set(desc, ''); //the problem has gone
}
}
}
...
}
Thank to all of the people that support me with they points of view.

Issue with disappearing images on click event (javascript)

I am supposed to build a store for a a javascript assignment. The store has three items and a counter which tallies the total of the items. Each item is updated through a click event which changes the value based on a data attribute defined in the html. It then saves this to cookies and allows us to use what was stored when we get to a checkout page. The cookies store and the totals update, but unfortunately, each time the click event occurs, the image disappears. I have been scouring the code and I cannot see why this is happening. Can anyone help?
$(document).ready(function() {
$("#jeans-line").text(Cookies.get("jeans") || 0)
$("#jeanJacket-line").text(Cookies.get("jeanJacket") || 0)
$("#belt-line").text(Cookies.get("belt") || 0)
$("#total").text(Cookies.get("total") || 0)
//The DOM will be changed to the key value of each cookie or 0
$('.item').click(function() {
itemTotal = parseInt($(this).text())
oneMore = itemTotal + ($(this).data('cost'))
$(this).text(oneMore)
Cookies.set($(this).data('name'), oneMore)
setTotal()
});
// //updating the total cost of the pseudo-items in shopping
function setTotal() {
var jeans = parseInt(Cookies.get("jeans"))
var jeanJacket = parseInt(Cookies.get("jeanJacket"))
var belt = parseInt(Cookies.get("belt"))
Cookies.set("total", (jeans + jeanJacket + belt) || 0)
$("#total").text(Cookies.get("total") || 0)
};
//Enter data and close the modal
var modal = $("#modal-box")
var email_input;
$(".email-submit").click(function(e) {
e.preventDefault();
email_input = $("#email-val").val()
console.log(email_input)
var checkEmail = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (checkEmail.test(email_input)) {
alert("This is a good email!")
Cookies.set("email", email_input)
modal.css("display", "none")
} else {
alert("This is not a valid email address!")
}
});
//closes the model with close click event
$(".close").click(function() {
modal.css("display", "none");
});
}) //closes document.ready
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="col-md-4">
<div class="item" data-cost="200" data-name="jeans">
<img id="jeansIMG" src="images/jeans.jpg">
<h2 class="item" id="jeans-line"></h2>
</div>
</div>
<div class="col-md-4">
<div class="item" data-cost="300" data-name="jeanJacket">
<img id="jeanJacketIMG" src="images/jean_jacket.jpg">
<h2 class="item" id="jeanJacket-line"></h2>
</div>
</div>
<div class="col-md-4">
<div class="item" data-cost="50" data-name="belt">
<img id="beltIMG" src="images/belt.jpg">
<h2 class="item" id="belt-line"></h2>
</div>
</div>
</div>
<!-- closes the bootstrap row -->
<div class="row">
<div class="col-md-4">
</div>
<div class="col-md-4">
<img class="shoppingCart" src="images/shopping_cart.jpg">
<h2 class="totalTitle">The total for these pseudo-products is:</h2>
<h2 id="total"></h2>
</div>
<div class="col-md-4">
</div>
</div>
The reason why images are getting remove is because of this code:
$('.item').click(function () {
itemTotal = parseInt($(this).text())
oneMore = itemTotal + ($(this).data('cost'))
$(this).text(oneMore) // <-- this overrides everything inside div.item
Cookies.set($(this).data('name'), oneMore)
setTotal()
});
Seeing your overall code, I'd suggest to change inner item class to something else (eg. item-total) so it won't be conflicting with the outer item class. After that adjust the javascript code:
$('.item').click(function() {
itemTotal = parseInt($(this).text())
oneMore = itemTotal + ($(this).data('cost'))
$('.item-total', this).text(oneMore) // <!-- change text in item-total
Cookies.set($(this).data('name'), oneMore)
setTotal()
});
You may also want to modify the setTotal to add default value || 0 so that it will calculate the total properly even if there is one or more items left unclicked:
function setTotal() {
var jeans = parseInt(Cookies.get("jeans") || 0)
var jeanJacket = parseInt(Cookies.get("jeanJacket") || 0)
var belt = parseInt(Cookies.get("belt") || 0)
Cookies.set("total", (jeans + jeanJacket + belt) || 0)
$("#total").text(Cookies.get("total") || 0)
};
You can check the simplified demo in https://jsfiddle.net/nm5dL9h1/

How do I make json get to work in angularJS?

I followed information on this answer
But it doesn't work in my situation.
Chrome Inspector console says "ReferenceError: dataResponse is not defined"
maybe that is the problem?
I am trying to GET this JSON from url:
[{"app_id":1,"app_name":"oh yeeah","app_description":"desc","app_price":111,"is_activated":false,"video":"videolink"},{"app_id":2,"app_name":"oh yeaaaeah","app_description":"ewaewq","app_price":222,"is_activated":false,"video":"fuck off"},{"app_id":3,"app_name":"oh yeaaaeah","app_description":"ewaewq","app_price":333,"is_activated":false,"video":"fuck off"}]
This is my javascript code
var appstore = angular.module('appstore', []);
appstore.service('dataService', function($http) {
delete $http.defaults.headers.common['X-Requested-With'];
this.getData = function(callbackFunc) {
$http({
method: 'GET',
url: '/administrator/components/com_apps/loadAppsJson.php'
}).success(function(data){
callbackFunc(data);
}).error(function(){
alert("error");
});
}
});
appstore.controller('app_Ctrl', function($scope, dataService) {
$scope.apps = [
{app_id:1, app_name:'oh yeah', app_description:'$app_description', app_price:111, is_activated:false, video:'$videolink'},
{app_id:2, app_name:'oh yeah', app_description:'$app_description', app_price:111, is_activated:false, video:'$videolink'},
{app_id:3, app_name:'oh yeah', app_description:'$app_description', app_price:111, is_activated:false, video:'$videolink'},
];
//$scope.apps = null;
dataService.getData(function(dataResponse) {
$scope.apps = dataResponse;
alert(dataResponse);
});
console.log(dataResponse);
console.log($scope.apps);
//get images thumbs
for(app = 0; app <= $scope.apps.length-1; app++) {
$scope.apps[app].thumb = ("000" + $scope.apps[app].app_id).slice(-3);
}
//separate apps to columns
var columns = [];
for (var i = 0; i < $scope.apps.length; i++ ) {
if (i % 3 == 0) columns.push([]);
columns[columns.length-1].push($scope.apps[i]);
}
$scope.columns = columns;
});
My HTML view
<div ng-controller="app_Ctrl">
<div class="row"></div>
<div class="row">
<div class="row" ng-repeat="apps in columns">
<div id="app_id_{{ app.app_id }}" class="col-lg-4" ng-repeat="app in apps | filter:search">
<div class="thumbnail" ng-class="app.is_activated ? 'activated' : ''">
<!-- -->
<img ng-src="/images/apps/app_images/{{ app.thumb }}_thumb.jpg" alt="{{ app.app_name }}" title="{{ app.app_name }}">
<div class="caption">
<h3>{{ app.app_name }}</h3>
<p class="app_price">{{ app.app_price }} €</p>
<div style="clear:both;"></div>
<p class="app_card_description">{{ app.app_description | limitTo:100 }}...</p>
Info
Video <span class="glyphicon glyphicon-facetime-video"></span>
{{ app.is_activated ? 'Aktivované' : 'Aktivovať' }}
</div>
</div>
</div>
</div>
To elaborate on what #Mritunjay said in the comments; review this code with comments:
dataService.getData(
// this is your callback function which has an argument for dataResponse
// the dataResponse variable will only be defined within the Call back function
function(dataResponse) {
$scope.apps = dataResponse;
alert(dataResponse);
// The Curly Brackets that follow mark the end of the callback handler method
});
// This log statement is not in the callback handler and there is no defined dataResponse variable which is probably why you got an error in the console
console.log(dataResponse);
You can fix this by moving the dataResponse log into the callback method, like this:
dataService.getData(function(dataResponse) {
$scope.apps = dataResponse;
alert(dataResponse);
console.log(dataResponse);
});
There appear to be other problems with your code, in that you are trying to access $scope.apps before the data is returned; which will hinder your processing. Easiest approach would be to move that processing into the result handler:
// define $scope.columns outside of the result handler
$scope.columns = [];
// call to method in service
dataService.getData(function(dataResponse) {
$scope.apps = dataResponse;
alert(dataResponse);
console.log(dataResponse);
// inside the result handler; you run this code after $scope.apps is defined:
for(app = 0; app <= $scope.apps.length-1; app++) {
$scope.apps[app].thumb = ("000" + $scope.apps[app].app_id).slice(-3);
}
//separate apps to columns
var columns = [];
for (var i = 0; i < $scope.apps.length; i++ ) {
if (i % 3 == 0) columns.push([]);
columns[columns.length-1].push($scope.apps[i]);
}
$scope.columns = columns;
});
That's what promises and asynchronous calls are all about.
console.log(dataResponse);
console.log($scope.apps);
The first one won't work because dataResource is a private variable and not part of the same scope you're trying to print.
The second one won't work either because that get's populated at future time (after X seconds), after the $http request is finished so it will only be availableat that point.
One way to do something after the object is populated is to use
$scope.$watch("apps", function (){
// do stuff
});

DOM reading in jquery

I'm trying to do a filter that will show or hide <div> regarding the data-type they have in their tags.
Here is my Javascript :
var course_difficulty_level_filter= function(el,level)
{
this.el = el;
this.el.closest('#courses_content').find("div").hide();
if(level != "00"){
this.el.closest('#courses_content').find('div[data-difficulty="'+level+'"]').show();
console.log("show difficulty_level : "+ level);
} else {
this.el.closest('#courses_content').find("div").show();
console.log("show difficulty_level : all");
};
}
$('#course_filter_level1').click(function(){
$(this).click(course_difficulty_level_filter($(this),"1"));
});
And here is my HTML :
<div id="coursefilter">
<div id="coursefilter_content" class="hide">
<div id="coursefilter_content_text">
<div id="course_filter_level_text"><p class="course_filter">Level: </p></div>
</div>
<div id="coursefilter_content_icons">
<div id="course_filter_level">
<div id="course_filter_level1" class="opacityquarter">
<div id="level1_rectangle1"></div>
<div id="level1_rectangle2"></div>
<div id="level1_rectangle3"></div>
<div id="level1_rectangle4"></div>
</div>
</div>
</div>
</div>
</div>
<!--Courses - Course Overviews-->
<div id="courses">
<div id="courses_content" class="hide">
<div class="course_overview_content_even" data-difficulty="1" data-lang="en"></div>
</div>
</div>
I successfully get the console.log => show difficulty_level : 1, so my script is "working", but I think it can't navigate trough the DOM, but I don't find why.
Are you simply looking for:
$('div[data-difficulty="'+level+'"]').show();
$('div[data-difficulty="'+level+'"]').hide();
jQuery has rich support for querying HTML attibutes: http://api.jquery.com/category/selectors/attribute-selectors/
I think this code is the problem:
this.el.closest('#courses_content')
The closest function works back up the parents to find the selector, but #courses_content is not a parent of #course_filter_level1 (the value passed in as el).
Try changing those references to just be:
$('#courses_content')
There should be no need to find this element relative to the passed in element as I hope there is only one div with the id courses_content as ID's are supposed to be unique within the document.
The whole function can be changed to this:
// removed el, so it must be removed from the calling function
var course_difficulty_level_filter= function(level)
{
var coursesContent = $('#courses_content');
coursesContent.find("div").hide();
if(level != "00"){
coursesContent.find('div[data-difficulty="'+level+'"]').show();
console.log("show difficulty_level : "+ level);
} else {
coursesContent.find("div").show();
console.log("show difficulty_level : all");
};
}

Categories