cursor.observe({added}) behavior in Meteor - meteor

I'm trying to display an alert to the user when data is added to the database. So I wrote (on the client side) :
Meteor.autosubscribe(function() {
ItemCollection.find().observe({
added: function(item) {
// Alert code
}
});
});
And I found that not only alerts are displayed when a new item is added to the database on the server side ( which I suppose is normal :) ) but alerts are also displayed for each previously added item when I refresh the page. I suppose Meteor fetch all the data from the Mongo database on startup (to populate the local Minimongo DB) and then fires 'added' event for each item added in the local database.
But is this the normal behavior ? How can I receive only items that are "truly" added in the database on the server ?

You are observing a cursor for the client side database and that database may not finish syncing until after the page is done loading, so the behavior makes sense. You may want to look into explicitly subscribing to a collection as discussed in the answer to this question.
If your data had a created_at field then you could observe items created after the page loads.
ItemCollection.find({created_at : {$gt: some_current_time}}).observe({
added: function(item) {
// Alert code
}
});

Related

Display twitter name and avatar in meteor app

Im building and app using meteor and ionic and i want to display the name and the avatar of the user logged in.
I wrote this
<img src="{{Meteor.users().services.twitter.profile_image_url}}">
but it is not working. The same query in my console returns the right result. Is it becaus i removed autopublish ? Is there a way to overcome this?
Define a helper then use it for the URL
Template.templateName.helpers({
imageUrl: function(){
return Meteor.user().services.twitter.profile_image_url;
//you wrote Meteor.users() which should be user()
}
});
Then use it in your HTML
<img src="{{imageUrl}}">
EDIT:
Meteor.user() will return the current user object. If you want the user's profile picture to be visible somewhere to other users or even if that user is not logged in, you should store user's id and use that id to find & return user object or some specific data. For example, if you have a posts collection, you can do the following...
//inside your insert post method, save userId
owner: this.userId
//usage in template helper where you have the post data
userObj: function(){
return Meteor.users.findOne(this.owner) //returns user object.
}
//HTML
{{userObj.someData}}
To overcome removal of autopublish you can publish your collection data in a server javascript file and subscribe to same collection in a client javascript file.
Also you can do the following for your own image collections, better implementation in my point of view:
in a HTML file where you get your userId from router:
<img src="{{getUserProfileImage userId}}">
in a client javascript file like common.js
Template.registerHelper('getUserProfileImage', function(userId) {
return UserImages.findOne({userId: userId}).image;
}
});
You should better store each image in a collection like I did. Also using Meteor.user() directly may cause errors if user hasn't logged-in.
Please add javascript tag to your codes for formatting.

FullCalendar (1.6) difficulty updating existing event on calendar with renderEvent

I'm using an older version of fullCalendar (1.6.4) with mostly success. I've got a UI that has the ability to add new events to the calendar, and then edit them inline. I'm running into problems when I try to then update the calendar with the modified event object. I'm only running into this problem however with dynamically added events, I can apparently reload the page and update events that fullCalendar adds initially just fine.
The problem seems very related to how the event.source property works. When the property is null on the event, fullCalendar pushes a new instance of the event onto the "cache" object, even if the event otherwise exists on the calendar already. I'm not sure why or how this works. For whatever reason though, I then end up with duplicate instances of the event on the calendar day.
// code directly from fullCalendar 1.6.4
function renderEvent(event, stick) {
console.log('renderEvent',event)
normalizeEvent(event);
if (!event.source) {
if (stick) {
stickySource.events.push(event);
event.source = stickySource;
}
cache.push(event);
}
reportEvents(cache);
}
So, in cases that are a pure edit of an existing calendar item, I make sure the source value is set and not lost/nulled anywhere. Even if worst case it does the below and sets it to an empty object. (Note, this may be a cause of my problems, I just don't know enough about full calendar). Sometimes I even have to force it to be {}, otherwise it has multiple items in source and I again end up with duplicate calendar entries after updating.
calEvent.source = calEvent.source ? calEvent.source : {};
I then update my existing calendar with a call to renderEvent.
$('#calendar').fullCalendar( 'renderEvent', calEvent, true);
Unfortunately, I'm running into the case where the new calEvent sent to renderEvent is updated, and it does not update the instance on the calendar. This may be because of the source field? And it only happens for newly dynamically added events.
Can someone assist about how to properly edit events? And how this source field should properly be used.

Update count for external link

I have a Meteor app for storing my bookmarks. To do that there is a Links collection with a count attribute. Every time I click the bookmark, the external site must be visited, but also the count must be increased with 1, so I can sort the bookmarks with the most visited at the top.
So now I have a link with the info in it:
{{title}}
Should I use a template instead, update the count and do a Router.go to the external site?
A little modification:
{{title}}
Then you could use:
Template.body.events({
'click a.tracked' : function(e) {
var href = $(e.currentTarget).attr('href');
ClickedLinks.insert({href: href, when: new Date()});
}
});
Where ClickedLinks is a collection. The main idea is that we track all click events on meteor body as a catch-all since everything is rendered in the body anyway even if it's in another template.. everything still winds up getting rendered there. Then we try to depend on events propagation to do our magic.
Here it is in action:
http://meteorpad.com/pad/Wtz6autqgCDEaJTLw/Leaderboard

meteor - live code update to webpage?

I'm curious to know whether Meteor would be suitable for following, and how I would go about writing the code.
I'd like to create a webpage, where by the code in a specific "div" can be hotswapped on the fly to users currently looking at that page. (eg. the div contains some text, but then an image replaces it.) Ideally, the swap would be executed manually by the the webpage's admin through the click of a button, or some code fired off on the server or something. Regular viewers to the webpage would not be able to do this - they only see the live changes on the page.
real-life example:
live internet broadcast is off-air, therefore the "div" contains "off-air" text. live hotswap of code happens when broadcast goes on-air, and the viewers of the webpage now see the html5 broadcast player in the "div" instead. later it is swapped back once the broadcast goes off-air.
I'm completely new to the Meteor platform, so I consider myself a newbie :) Any help is appreciated.
You might better off by using a reactive div using data from a collection (I'm going to use an example with raw HTML but you might be better off implementing your own functionality with what content to display instead: i.e
Basically take advantage of reactivity over hot code swaps
Client side html code
<template name="home">
<div>
{{{content}}}
</div>
</template>
js code
if(Meteor.isClient) {
MyCollection = new Meteor.Collection("MyCollection")
Template.home.content = function() {
if(MyCollection.findOne()) {
return MyCollection.findOne().content
}
}
}
if(Meteor.isServer) {
MyCollection = new Meteor.Collection("MyCollection")
//Set an initial content if there is nothing in the database
Meteor.startup(function() {
if(!MyCollection.findOne()) {
MyCollection.insert({content:"<h1>Test content</h1><p>Test Data</p>"
}
}
//A method to update the content when you want to
Meteor.methods({
'updatecontent':function(newcontent) {
id = MyCollection.findOne()._id
MyCollection.update(id, {$set:{content:newcontent}});
return "Done"
}
}
You can update your content either in the mongo collection or with something like (in your web console, client side or server side javascript):
Meteor.call("updatecontent","New content",function(err,result) {
if(!err) {
console.log(result)
}
});
Which will update the code live when you use it.
I'm sorry it's quite long but the bulk of it is setting/updating the html. Its actually much nicer than a hot code swap which would refresh the user's page

Replacement for window.sessionStorage in Javascript?

I have an application with a launch page that needs to determine what is already opened, so it does not reopen things that are opened already in another new tab. In Firefox, I was able to make this work, by using window.sessionStorage to store the titles of pages that are open, and then use window.opener with the following code to remove the titles from the list.
Gecko Session Storage Info Page
if (window.sessionStorage) {
if (window.sessionStorage.getItem(code)) {
return; // page already open
}
else {
window.sessionStorage.setItem(code, code);
window.open("Sheet.aspx", "_blank");
}
}
And on the pages that are opened:
function signalPageExit() {
if (window.opener.sessionStorage) {
window.opener.sessionStorage.removeItem(
document.getElementById("runcode").childNodes[0].textContent);
}
This doesn't work in IE so I decided to use a cookie strategy, but the cookies were never successfully deleted from code on the dynamically launched pages, and therefore pages couldn't be reopened from the launch page once they had been launched until the cookie expired.
My second attempt was to define my own sessionStorage when it did not exist. That looked like this:
function setStoreItem(name, val) {
this.storage[name] = val;
}
function getStoreItem(name) {
return(this.storage[name]);
}
function removeStoreItem(name) {
this.storage[name] = null;
}
function sesStorage() {
this.storage = new storageData();
this.setItem = setStoreItem;
this.getItem = getStoreItem;
this.removeItem = removeStoreItem;
}
// storage object type declaration
function storageData() {
}
// IE 7 and others
else {
window.sessionStorage = new sesStorage();
window.sessionStorage.setItem(code, code);
window.open("Sheet.aspx", "_blank");
}
But it seems the real session storage is special, this ordinary object of the window did not stay alive across postbacks and therefore when my launch page posted back, the list of created page titles was wiped out.
So now I'm looking for a way to make this work. I have a launch page called scoresheets.aspx that creates dynamic pages based on user requests. These pages share a substantial amount of javascript code that can be modified to make this work.
I don't want to refresh the launched pages when a user tries to reopen them, but if there is some way to detect the titles of opened pages or some other way to use window.opener to communicate with the same persistence that sessionStorage has, I'd be glad to use it.
Eric Garside’s jStore plugin provides a jquery based api to several client side storage engines.
you should go with that cookie strategy and set those cookies to expire when the windows (tab) is closed. that should work across browsers.

Resources