creating reactive array session storage - javascript

I'm trying to exclude documents to show on client based on user event.
this is my attempt which failed:
Template.documents.events({
'click #dontShowThisDocument': function () {
Session.set('excludedDocument', this._id);
}
});
Template.documents.helpers({
lists: function () {
var excludedDocuments = [];
excludedDocuments.push(Session.get('excludedDocument'));
return Coll.find({_id:{$nin:excludedDocuments});
}
});
how to create array session storage with meteor so then the user able to exclude certain document on a list reactively ?
Thank You so much.

A Session variable can hold an array (or any object really) which means you could do this:
Template.documents.events({
'click #dontShowThisDocument': function () {
var excluded = Session.get('excludedDocument');
if ( excluded ) excluded.push(this._id);
else excluded = [ this.id ];
Session.set('excludedDocument',excluded);
}
});
Template.documents.helpers({
lists: function () {
return Coll.find({ _id: { $nin: Session.get('excludedDocument') });
}
});

Related

Meteor - How to give value from child to parent function?

I want to send value of result from child to parent element. I used Session.set and Session.get and it works fine but I know that is not good practice because Sessions are global. So, I wanted to try something like reactive var or reactive dict but both of them are giving me only object as a result. What should I do or how should I take specific things from that object? (I am storing JSON inside that ReactiveVar or Dict and I know that they are really bad with JSON. Thank you for help!
Template.companyCreate.helpers({
CompanyName : function () {
if (Meteor.user() || Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
//this is where I want to take result and give it to parent function
}
});
return //this is where I want to take result that was given from child function and return it to CompanyName
}
else {
Router.go('/nemate-prava')
}
},
UPDATED CODE
Template.companyCreate.onCreated(function Poruke() {
this.message = new ReactiveVar(' ');
let self = this;
let user = Meteor.user();
let companyNameHandler = Template.currentData().companyNameHandler;
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
companyNameHandler(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});
Template.companyCreate.helpers({
message: () => { return Template.instance().message.get() },
isNotInRole : function() {
if (!Meteor.user() || !Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
return true;
}
else {
return false;
}
},
CompanyName : function () {
return Template.instance().companyName.get();
}
});
Template.companyCreate.events({
'submit form': function(event, template) {
var Ime = event.target.Ime.value;
event.preventDefault();
Meteor.call('companyCheck', Ime, function(error, result) {
if (error) {
console.log(error.reason);
template.message.set(error.reason);
alert(error.reason);
}
else {
event.target.Ime.value = "";
console.log('Kompanija je uspesno kreirana!');
template.message.set("Uspesno!");
}
})
},
});
Method:
'findCompany'(){
ImeKompanije = firma.findOne({AdminID: this.userId}).ImeKompanije
if (typeof ImeKompanije == 'undefind') {
throw new Meteor.Error(err, "Greska!");
}
return ImeKompanije;
},
});
Router:
Router.route('/comp/:ImeKompanije', {
name: 'companyProfile',
template: 'companyProfile',
waitOn: function() {
return Meteor.subscribe('bazaFirmi', this.params.ImeKompanije)
},
action: function() {
this.render('companyProfile', {
data: function() {
return firma.findOne({ImeKompanije: this.params.ImeKompanije});
}
});
},
});
ok, there's a lot to unwind here. let's start with something small.
if (Meteor.user() || Roles.userIsInRole(Meteor.user(),['admin','adminCreator'], 'companyAdmin')) {
i think this line is meant to say, "if the user is an admin". but it's really saying, "if the user is logged in." if you meant the first one, then change the "||" to an "&&".
bigger issue is you're making a server call in a helper. helpers can get called over and over, so think of them as something that simply returns data. it should not have any side effects, such as making a server call or (yikes) re-routing the user.
so let's move all that side effect code to the onCreated() and capture the company name so it can be returned from the helper. We'll also get set up to return the company name to the parent.
Template.companyCreate.onCreated(function() {
let self = this;
let user = Meteor.user();
let companyNameHandler = Template.currentData().companyNameHandler;
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
companyNameHandler(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});
now the helper is really simple, it just returns the data that was saved to the template's reactive var:
Template.companyCreate.helpers({
CompanyName : function () {
return Template.instance().companyName.get();
}
});
the last part is setting up the handler to return the data to the parent. it's bad form to have the client reaching back up to its parent, so i usually have the parent give to the child a function it can call. usually i'll do that when the child says, "i've done my work," but here we can use it to provide that data. i'll have to make some assumptions on what your parent looks like.
<template name="Parent">
{{> companyCreate companyNameHandler=getCompanyNameHandler}}
</template>
Template.Parent.helpers({
getCompanyNameHandler() {
let template = Template.instance();
return function(companyName) {
console.log(companyName);
// you can also access the parent template through the closure "template"
}
}
});
the parent's helper returns a function that is passed to the client. when the client calls it, it will execute in the parent's closure. you can see i set up a variable called "template" that would allow you to, say, access reactive vars belonging to the parent.
UPDATE: in case the handler isn't known as is inside the Meteor.call() scope, we can try using it through a reactive var.
Template.companyCreate.onCreated(function() {
let self = this;
let user = Meteor.user();
self.companyNameHandler = new ReactiveVar(Template.currentData().companyNameHandler);
self.companyName = new ReactiveVar();
if (user && Roles.userIsInRole(user,['admin','adminCreator'], 'companyAdmin')) {
Meteor.call('findCompany', function(err, result) {
if (err) {
console.log(err.reason)
}
else {
self.companyName.set(result);
let fn = self.companyNameHandler.get();
fn(result);
}
});
}
else {
Router.go('/nemate-prava')
}
});

Meteor method clobbers subscribed query

I'm using Meteor with React. When I load a page, Iron Router creates a document in a collection. It then uses a Meteor.method to look up the user's permissions and set them on the document through and update. At the same time, the client page is loading and runs queries for the document in the collection.
It seems that the Meteor.method code is clobbering the query on the client. Through multiple queries, the document exists and I can console.log() it. Then suddenly I get "undefined". The document still exists because I can query it from another Meteor.call. I have used publish/subscribe, but the client can't see it.
Here's some of my code (files combined for simplicity):
Editors = new Mongo.Collection('editors');
if (Meteor.isServer())
Meteor.publish('editors', function (editorId) {
return Editors.find(editorId) || this.ready();
});
Meteor.methods({
setEditorMode: function (editorId, userId) {
var editor = Editors.findOne(editorId);
var role = Roles.find({
doc_id: editor.manuscriptId,
user_id: userId
}).fetch()[0];
var defaultEditorMode = "readOnly";
if (role !== null && role.role == 'owner' || role.role == 'contributor') {
defaultEditorMode = "readWriteComment";
} else if (role !== null && role.role == 'reviewer') {
defaultEditorMode = "readComment";
}
console.log(editor);
Editors.update(editor._id, {
$set: {
defaultEditorMode: defaultEditorMode,
editorMode: defaultEditorMode
}
});
console.log(Editors.findOne(editor._id);
}
});
}
if (Meteor.isClient()) {
Router.route('/documents/:id/edit', function () {
var editorId;
manuscriptId = this.params.id;
this.wait(/* Doing some work */);
if (this.ready()) {
editorId = Editors.insert({manuscriptId: manuscriptId});
Meteor.call('setEditorMode', editorId, Meteor.userId());
this.render('editor', {
data: function () {
return {
editorId: editorId
};
}
});
} else {
this.render('loading');
}
});
Editor = React.createClass({
mixins: [ReactMeteorData],
componentWillMount: function () {
Meteor.subscribe('editors', this.props.editorId);
},
getMeteorData: function () {
var editor, editorId;
editorId = this.props.editorId;
editor = Editors.findOne(editorId);
console.log(editor);
return {
editor: editor || {}
};
},
render: function () {
return <EditorContent editor={this.data.editor} />
}
});
}
I need to make the update on the server so that it can happen securely. My expectation was that any updates to the document on the server would propagate to the client. Instead, once I make the update on the server getMeteorData() gets called and the query returns "undefined".
How can I get the value I just set on the server?
Thanks to #ko0stick, I figured out that I needed to place my Meteor.subscribe code inside of getMeteorData

Define autoform hook for forms in for each in Meteor

I have a for each loop in Meteor and I'm using autoform to update each item (just like described at http://autoform.meteor.com/update-each).
My problem is that I normally create notifications through hooks with
AutoForm.hooks({
myFormId: {
onSuccess: function(formType, result) {
Notifications.success('Title', 'Text.');
}
}
});
but since all my forms have unique IDs, I cannot use this. How can I create a hook which matches all forms in a template or has a name which matches a regular expression "unique-id-?" where ? is the docId?
This may not be the optimal solution, but it works:
Template["updateEach"].helpers({
items: function () {
return Items.find({}, {sort: {name: 1}});
},
makeUniqueID: function () {
return "update-each-" + this._id;
}
});
Template.updateEach.onRendered(function () {
var hooksObject = {
onSuccess: function (formType, result) {
Notifications.success('Title', 'Text.');
}
};
var formIds = Items.find().map(function (item) {
return "update-each-" + item._id;
});
AutoForm.addHooks(formIds, hooksObject);
});

Lawnchair : check store and its document exists

I've created a Lawnchair store and saved it. See the following code:
var DB = new Lawnchair({ name: "DB", adapter: ["indexed-db", "webkit-sqlite", "ie-userdata", "blackberry-persistent-store", "dom", "window-name", "gears-sqlite", "memory"] });
DB.save({ key: "resKey", res: res});
Here res is a javascript object, it is the data that gets stored.
But when I close and reopen the web page the next time, I want to check whether this store exists. If the store exists, I want to check whether this document exists. How to do these checks?
Thanks
PS - Is there any good resource where I can learn Lawnchair?
Finally after a lot of trials, I came up with the following :
// create a store //* CORRECT TO USE
DB = new Lawnchair({ name: "DB", adapter: ["indexed-db", "webkit-sqlite", "ie-userdata", "blackberry-persistent-store", "dom", "window-name", "gears-sqlite", "memory"] });
//Save a document/table
DB.save({ key: "resKey", data: res }, function () {
//Access the created store
DB = Lawnchair({ name: "DB", adapter: ["indexed-db", "webkit-sqlite", "ie-userdata", "gears-sqlite", "blackberry-persistent-store", "dom", "window-name", "memory"] });
console.log(DB)
//check if the document exists based on the key we used to create it
DB.exists("resKey", function (e) {
console.log("exists : " + e)
if (e == true) {
//get all records from the store
DB.all(function (r) {
console.log(r);
//remove all document/table from the store
DB.nuke(function () {
console.log("Data nuke-ed");
//check if the document exists based on the key we used to create it
DB.exists("resKey", function (e) {
console.log("exists : " + e)
if (e == true) {
//get all records from the store
DB.all(function (r) {
console.log(r);
});
} else {
console.log("Data deleted");
}
});
});
});
} else {
}
});
});
Please let me know if this is the right way to do it or is there a better way. If you liked my effort give me points :)

How to set data in an action using IronRouter on Meteor?

How can I set additional data in an action function in a Meteor Application that uses IronRouter ? See comments in emailWelcome and emailContract functions below...
Code:
EmailController = RouteController.extend({
template: 'emailPage',
waitOn: function() {
return [
Meteor.subscribe('customers'),
];
},
data: function() {
var request = Requests.findOne(this.params._id);
if (!request)
return;
var customer = Customers.findOne({'_id': request.customerId});
if (!customer)
return;
return {
sender: Meteor.user(),
recipient: Customers.findOne({_id:Session.get('customerId')})
};
},
emailWelcome: function() {
// Set var in the context so that emailTemplate = 'welcomeEmail' here
this.render('emailPage');
},
emailContract: function() {
// Set var in the context so that emailTemplate = 'contractEmail' here
this.render('emailPage');
}
});
You can get access to the data with this.getData() in your action functions:
emailWelcome: function() {
var data = this.getData(); // get a reference to the data object
data.emailTemplate = 'welcomeEmail';
this.render('emailPage');
},
emailContract: function() {
var data = this.getData(); // get a reference to the data object
data.emailTemplate = 'contractEmail';
this.render('emailPage');
}
be careful not to call this.data(), as that will regenerate the
data instead of getting you a reference to the already generated data
object.
also be careful not to call this.setData(newData) within an action as that will invalidate the old data object, initiating a reactivity reload, and lead to an infinite loop!

Categories