Related items in Meteor - javascript

I have groups and items and the items are related to specific groups. At the "detail page" of a group I want to see all the items belonging to the specific group.
I've tried this
Router.route('/group/:_id', {
name: 'group',
template: 'group',
waitOn: function () {
return this.subscribe("groups", this.params._id);
},
data: function () {
return {
group: Groups.findOne(this.params._id);
items: Items.find({groupId: this.params._id}),
}
}
});
But what should waitOn look like if it should both wait for the specific group AND the items belonging to the group?

You can return an array of subscriptions to wait on:
waitOn: function () {
return [
Meteor.subscribe("groups", this.params._id),
Meteor.subscribe("items", this.params._id)
]
}

You can either have another publish function
Meteor.publish('relatedItems', function (groupId) {
return Items.find({groupId: groupId});
});
and wait for the two subscriptions
waitOn: function () {
return [
Meteor.subscribe("groups", this.params._id),
Meteor.subscribe("relatedItems", this.params._id)
];
},
or you can add to your existing publication like this:
Meteor.publish('groups', function (groupId) {
return [
Groups.find({_id: groupId}),
Items.find({groupId: groupId}),
];
});

Related

deep filtering on array of objects

I have data like this one below
let data = [
{
name: 'basic',
to: 'aaa',
subMenus: [
{
name: 'general conc',
to: 'geneal',
},
{
name: 'example view',
to: 'example',
},
{
name: 'fancy',
to: 'bbb',
innerSubMenus: [
{
name: 'adding',
to: 'add',
},
{
name: 'getting',
to: 'get',
},
]
}
]
}
]
I need to filter data based on name (in main, subMenus, and innerSubMenus)
Here is the piece of code
function deepFilter(inputText){
data.filter(items => items.name.toLowerCase().includes(inputText.toLowerCase()))
}
As you can see, the function filters the first prop (name --> basic in this case when inputText = 'basic', doesn't work when inputText = 'general conc') but I want to be able to filter names in subMenus and innerSubMenus as well. Please, guide me on how to do it. Thanks
expected outputs:
deepFilter('basic') -> true // only this part is covered by my implementation
deepFilter('general conc') -> true
deepFilter('adding') -> true
deepFilter('ffff') -> false //since there is not name with value of 'ffff' in data
I think this should work well.
function deepFilter(inputText, datas) {
return datas.filter(data => {
function checkInsideObj(object, inputText) {
for (let value of Object.values(object)) {
if (object.name && object.name.toLowerCase() === inputText.toLowerCase()) {
return true;
}
if (Array.isArray(value)) {
return value.some(item => {
return checkInsideObj(item, inputText)
}
)
}
}
return false;
}
return checkInsideObj(data, inputText)
}
)
}
deepFilter("input", data)

Array of functions - Javascript

I'm developing a vue-based system, and for my tables, I'm using this: https://github.com/matfish2/vue-tables-2
The component has lots of options. There's the possibility to define custom cell templates to manipulate data before showing them, like this one for the "created_at" column:
templates: {
created_at(h, row) {
return this.formatDate(row.created_at);
},
//(...)
}
I can add other templates as well:
var user_id = function(h,row){return row.id};
...
templates: {
created_at(h, row) {
return this.formatDate(row.created_at);
},
user_id,
(...) // etc
}
But I'd like to group the functions into a variable, so I could reuse the code, like:
var custom_template = [
{ user_id(h,row){return row.id} },
{ user_name(h,row){return row.name} },
{ created_at(h, row){return this.formatDate(row.created_at)} }
];
templates: {
custom_templates
}
EDIT 1:
So i could have something like:
templates: {
user_id(h,row){return row.id} ,
user_name(h,row){return row.name} ,
created_at(h, row){return this.formatDate(row.created_at)}
}
It's not working, but is it possible? Do I need extra code to achieve this?
Thanks! =)
var custom_template = [
function user_id(h, row) {
return row.id;
},
function user_name(h, row) {
return row.name;
},
function created_at(h, row) {
return row.created_at;
}
];
custom_template.forEach(
item => console.log(item(1, {
id: 1,
name: "test",
created_at: new Date()
})));
You need to combine Igor's solution to create array of functions with some form of expanding the array, such as the spread syntax

Meteor: Composite publish to get data from two collections

I try to use reywood:publish-composite. But something I'm doing wrong as I want to load the article-data and the assigned literature-data.
I think my main problem is to set the route correctly to get the data into the variables, which I could use in the template.
Persume I would open /article/BpsCfbhZuoXfEvREG:
publications.js
Meteor.publishComposite('articles', function(){
return {
find: function(){
return Articles.find();
},
children: [{
find: function(article){
return Literature.find({'article.detail.reference': article._id})
}
}]
}
});
router.js
Router.route('/article/:_id', {
name: 'article',
waitOn: function() {
return Meteor.subscribe('articles'); /* correct? */
},
data: function () {
return {
article: Articles.findOne({
_id: this.params._id
}),
references: Literature.find({}) /* guess, this is wrong */
};
}
});
Literature has this structure and I'm looking for reference:
{
"_id" : "YAEYvJ7tvXxTvnFtv",
"article" : [
{
"title" : "Article 1",
"detail" : [
{
"reference" : "BpsCfbhZuoXfEvREG",
"year" : 2000,
}
]
}
]
}
You want to load an individual article? That looks like what you are doing but you are subscribing to all articles. You could pass the parameter to your subscription.
waitOn: function () {
return Meteor.subscribe('article', this.params._id);
}
Secondly, since your Literature is an array of objects, you should use $elemMatch
Meteor.publishComposite('article', function (articleId) {
check(articleId, String);
return {
find: function () {
return Articles.find(articleId);
},
children: [{
find: function (article) {
return Literature.find({
'article.detail': {
$elemMatch: {
'reference': article._id
}
}
});
}
}]
}
});

Knockout mapping and parent options

I'm tring to map this
{ items: [
{ id: 1 },
{ id: 2 },
{ id: 3 }
]};
when creating something in the array I add a function to remove the item from the collection.
var mapping = {
'items': {
key: function(data) {
return ko.utils.unwrapObservable(data.id);
},
create: function(options) {
var o = (new(function() {
this._remove = function() {
options.parent.items.mappedRemove(options.data);
};
ko.mapping.fromJS(options.data, {}, this);
})());
return o;
}
}
};
this method works if I am removing an item added using items.mappedCreate but donĀ“t work with the items mapped on ko.mapping.fromJS.
When debugging I noticed that options.parent are not the same in the different situation.
Why? Should both methods return as parent the items observableArray?
I have set up a jsfiddle with an example http://jsfiddle.net/fampinheiro/9CcME/.
Thank you
I posted my problem in knockout ggroups
https://groups.google.com/d/topic/knockoutjs/cqBr_CPsfqc/discussion
and Roy Jacobs solved my jsfiddle problem.

Calling function defined in an object

I have an object that defines the name and parameters of a function to be called in the click event of a page element.
object_array = [
{
id: "id1",
onclick: "load_file(filename.php);",
},
{
id: "id2",
onclick: "open_url('http://url.com');",
}
];
That information must be retrieved dynamically. I'd like in the click event to call the onclick function for a given object in the array.
$('element').click(function() {
// call object.onclick
});
Seems that eval() is not a good choice. Is there a different way of calling that function?
You should refactor the object_array to:
[{
id: "id1",
action: "load_file",
url: "filename.php"
}, {
id: "id2",
action: "open_url",
url: 'http://url.com'
}];
Then you can call it with:
var actions = {
load_file: function(url) {
...
},
open_url: function(url) {
...
},
...
};
object_array.forEach(function(ob) {
$("#"+ob.id).click(function() {
actions[ob.action](ob.url);
});
});
If you have more complex arguments, you could also deliver an arguments array instead of url and use apply() on the function.
Or, if you just want a lookup-table of functions, use:
var object = {
"id1": function() {
load_file('filename.php');
},
"id2": function() {
open_url('http://url.com');
}
};
$('element').click(function() {
object[this.id]();
});
Here's a working jsfiddle:
http://jsfiddle.net/Zh6Fv/1/
Like so:
object_array = [
{
id: "id1",
// Encapsulate in an anonymous function
onclick: function(){ load_file('filename.php'); },
},
{
id: "id2",
// Encapsulate in an anonymous function
onclick: function(){ open_url('http://url.com'); },
}
];
Then actually bind it it like this ::
$('element').click(obj.onclick);
Presumably you would be using it like this::
object_array.forEach(function(obj){
// Note there is no need to wrap the obj.onclick
// into another anonymous function anymore!
$("#" + obj.id).click(obj.onclick);
});
Here's a working jsfiddle:
http://jsfiddle.net/Zh6Fv/1/
you can declare a function like
onclick : function()
{
action(arguments);
}

Categories

Resources