My application is publishing a 'memberPrice' field when it is not supposed to. In my publish.js file, I specified the memberPrice to not be published. Here is my server/publish.js:
Meteor.publish('cars', function() {
return Products.find({category: 'vehicle'}, {limit: 10}, {fields: {memberPrice: 0}});
});
My controller:
carsController = RouteController.extend({
waitOn: function () {
var sessionId = Session.get('sessionId');
console.log("Session: ", sessionId);
Meteor.subscribe('cars');
Meteor.subscribe('cartItems', sessionId);
},
action: function() {
this.render('Cars');
}
});
Here's my table using the aldeed:tabular package:
TabularTables = {};
Meteor.isClient && Template.registerHelper('TabularTables', TabularTables);
TabularTables.Cars = new Tabular.Table({
name: "Cars",
collection: Products,
columns: [
{data: "productCode", title: "Product Code"},
{data: "brand", title: "Brand"},
{data: "productLineName", title: "Product Name"},
{data: "description", title: "Description"},
{data: "memberPrice", title: "Member Price"}
]
});
Does anyone know what's going on?
Thanks!
You're passing three arguments to Products.find, but it only expects two. {limit: 10}, {fields: {memberPrice: 0}} should be {limit: 10, fields: {memberPrice: 0}}.
In the past i do publish like the one you have, but since i read this post from David Weldon page.
I change my publish to something like this.
Meteor.publish('cars', function() {
var selector = {category: 'vehicle'};
var options = {limit: 10,fields: {memberPrice: false}};
return Products.find(selector,options);
});
Based on the Publish function you have, the memberPrice option should be exclude here, try with this, here we are following the correct syntaxis of the Collection.find wich is collection.find([selector], [options]) and you have something like collection.find([selector],[selector],[options]).
Related
I'm pretty new with vue.js and I saw this great library that doing exactly what I need for my project: Boostrap-Vue
example source code
I followed the basic instructions and I've added an small change, ajax call for dynamic content:
<layout :docs="docs">
<template slot="demo">
<b-table
stripped
hover
:items="items"
:fields="fields"
:current-page="currentPage"
:per-page="perPage"
:filter="filter"
>
<template slot="name" scope="item">
{{item.value.first}} {{item.value.last}}
</template>
</b-table>
</template>
</layout>
export default {
mounted () {
this.get_data();
},
data() {
return {
docs: {
component: 'bTable'
},
items: [],
fields: {
name: {label: 'Person Full name', sortable: true},
},
currentPage: 1,
perPage: 5,
filter: null
};
},
methods: {
get_data () {
this.$http.get("myapp/users").then(res => {
if (res.body) {
this.items = res.body;
} else {
this.error = true;
}
});
}
}
};
So the problem is - after I'm getting the Ajax response and the "items" variable initialized with the data but the table still won't get update.
The strangest part is that with static data its works fine (as shown in the example source code, without AJAX).
Any idea why?
Thanks!!!
I found the problem, it seems that it necessary to define the following fields according to the value I received in the response:
fields: {
name: {label: 'Person Full name', sortable: true},
}
so if my json looks like this:
{user_name: "user"}
it should look like this:
fields: {
user_name: {label: 'Person Full name', sortable: true},
}
Anyway, Yoram de Langen Thanks for the help!
Did you try to debug the res.body and what it contains? What is the structure your myapp/users returns? Do you return the structure directly like so:
[
{ "name": "item 1"},
{ "name": "item 1"},
]
or does it look like this:
{
"result": [
{ "name": "item 1"},
{ "name": "item 1"},
]
}
In case of the latest one your this.items = res.body should be: this.items = res.body.result
I'm creating a recipe-database (commonly known as a cookbook) where I need to have a many-to-many relationship between ingredients and recipes and I'm using sequelize.js in combination with postgresql.
When an ingredient is added to a recipe I need to declare the correct amount of that ingredient that goes into the recipe.
I've declared (reduced example)
var Ingredient = sequelize.define('Ingredient', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var Recipe = sequelize.define('Recipe', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var RecipeIngredient = sequelize.define('RecipeIngredient', {
amount: Sequelize.DOUBLE
});
Ingredient.belongsToMany(Recipe, { through: RecipeIngredient });
Recipe.belongsToMany(Ingredient, {
through: RecipeIngredient,
as: 'ingredients'
});
My problem is with how data is returned when one my REST endpoints do
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients'
}]
}).then(function(r) {
return res.status(200).json(r[0].toJSON());
})
});
The resulting JSON that gets sent to the client looks like this (timestamps omitted):
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"RecipeIngredient": {
"amount": 12,
"RecipeId": 1,
"IngredientId": 1
}
}
]
}
While all I wanted was
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"amount": 12,
}
]
}
That is, I want the amount field from the relation-table to be included in the result instead of the entire RecipeIngredient object.
The database generated by sequelize looks like this:
Ingredients
id name
1 carrot
Recipes
id name
1 Carrots
RecipeIngredients
amount RecipeId IngredientId
12 1 1
I've tried to provide an attributes array as a property to the include like this:
include: [{
model: Ingredient,
as: 'ingredients',
attributes: []
}]
But setting either ['amount'] or ['RecipeIngredient.amount'] as the attributes-value throws errors like
Unhandled rejection SequelizeDatabaseError: column ingredients.RecipeIngredient.amount does not exist
Obviously I can fix this in JS using .map but surely there must be a way to make sequelize do the work for me?
I am way late to this one, but i see it been viewed quite a bit so here is my answer on how to merge
attributes
Some random examples in this one
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
})
.then(docs =>{
const response = {
Deal: docs.map(doc =>{
return{
cakeRecipe:doc.recipe1,
CokkieRecipe:doc.recipe2,
Apples:doc.ingredients.recipe1ingredient
spices:[
{
sugar:doc.ingredients.spice1,
salt:doc.ingredients.spice2
}
]
}
})
}
})
res.status(200).json(response)
})
You can use sequelize.literal. Using Ingredient alias of Recipe, you can write as follows. I do not know if this is the right way. :)
[sequelize.literal('`TheAlias->RecipeIngredient`.amount'), 'amount'],
I tested with sqlite3. Received result with alias "ir" is
{ id: 1,
name: 'Carrots',
created_at: 2018-03-18T04:00:54.478Z,
updated_at: 2018-03-18T04:00:54.478Z,
ir: [ { amount: 10, RecipeIngredient: [Object] } ] }
See the full code here.
https://github.com/eseom/sequelize-cookbook
I've gone over the documentation but I couldn't find anything that seems like it would let me merge the attributes of the join-table into the result so it looks like I'm stuck with doing something like this:
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
}).then(function(recipes) {
return recipes[0].toJSON();
}).then(function(recipe) {
recipe.ingredients = recipe.ingredients.map(function(i) {
i.amount = i.RecipeIngredient.amount;
delete i.RecipeIngredient;
return i;
});
return recipe;
}).then(function(recipe) {
return res.status(200).json(recipe);
});
});
Passing through to include lets me filter out which attributes I want to include from the join-table but for the life of me I could not find a way to make sequelize merge it for me.
The above code will return the output I wanted but with the added overhead of looping over the list of ingredients which is not quite what I wanted but unless someone comes up with a better solution I can't see another way of doing this.
I have made a Model which I made to display the whole discography of a band which I get delivered by an API as JSON. So far so good, but I need to sort the albums by its releasedate, so I intent to use the comparator-method, which is not possible to use on Models. So I want to "transform" the Model into a Collection, or is there maybe a better way?
Here is my model I define on my discography.js:
ArtistDiscography.ArtistDiscographyModel = Backbone.Model.extend({
url: function() {
return App.APIO + '/i/artist/' + this.get('slug') + '/releases';
},
parse: function(response){
return response.data;
},
});
the slug value is the JSON value, which returns for example rihanna. The JSON file also contains a value called releaseDate.
In my maincontroller.js, I have this:
define(function (require, exports, module) {
var ArtistDiscographyModule = require('modules/discography');
)};
ArtistController.prototype.initDiscography = function(name) {
this.artistdiscographyModel = new ArtistDiscographyModule.ArtistDiscographyModel({slug: name});
this.artistdiscographyModel.fetch();
this.artistdiscographyModel.on('sync', function() {
this.artistDiscographyView = new ArtistDiscographyModule.View({model: this.artistdiscographyModel});
App.useLayout('artistDiscography', 'artistDiscography').setViews({
'.releasesDiv' : this.artistDiscographyView,
}).render();
}, this);
};
The JSON response is:
data: [{
"slug" : "rihanna",
"releases": {
"title" : "Music Of The Sun",
"releaseDate": "2005-08-29",
"tracks": [{ //array of tracks}]
}, {
"title" : "Pon de Replay",
"releaseDate": "2005-08-22"
"tracks" : [{ //array of tracks}]
}
}]
Can someone help me out? I would really appreciate it!
You can set collection as an attribute of model:
ArtistDiscography.ArtistDiscographyModel = Backbone.Model.extend({
defaults: {
slug: '',
releases: new Releases()
}
});
Releases = Backbone.Collection.extend({
model: Release
});
Release = Backbone.Model.extend({
defaults: {
title: '',
releaseDate: '',
tracks: []
}
});
Then you can add comparator into Releases collection.
Or you can go dirty and use the underscore's sort function for array:
_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]
Have you tried something along these lines?....
ArtistDiscographyCollection = Backbone.Collection.extend({
model: ArtistDiscography.ArtistDiscographyModel,
comparator: function (model) {
return (model.get('releases').releaseDate);
}
});
So I'm working with a Kendo Grid and how it's headers are grouped. One option that I have working currently is for the Grid to grab my list and sort group by checking every element in that list. So I get something like:
->Roles:
->Roles: Tester, Manager, Team Lead
->Roles: Tester
->Roles: CEO, Tester
->Roles: Team Lead, CEO
(you get the idea). This is because "Roles" in my database model are in a list (since a person can have many roles) and the Kendo Grid is comparing every element in that list. However, I want it to group by just the first element in each person's list so I instead get something like:
->Roles: Tester
->Roles: Manager
->Roles: Team Lead
->Roles:
->Roles: CEO
etc. Does anyone know how to do this? Currently I am doing
group: {
field: "RoleName",
aggregates: [
{ field: "ResourceName", aggregate: "count" },
{ field: "OrganizationName", aggregate: "count" }
]
},
And I assume that I want to be doing something more along the lines of:
group: {
field: "RoleName.get(0)",
aggregates: [
{ field: "ResourceName", aggregate: "count" },
{ field: "OrganizationName", aggregate: "count" }
]
},
However, I'm not familiar enough with Kendo Grid to know the syntax to do this correctly. Thanks in advance for all help!
Edit: I should add that because many of the people that will be using this still need IE8 support, I am using Kendo Grid imports from /2012.2.710 instead of the latest update
*Edit My Answer assumes the user loads the data outside the function and doesn't hard code in the data.
Try using the parse function in schema,
I'll just add to what you should have in your project already, for example:
$('.grid').kendoGrid({
dataSource: {
schema: {
parse: function(data) {
for (var i = 0; i < data.length; i++) {
data[i].firstWord = data[i].name.split(' ')[0];
}
return data;
}
}
group: {
field: "firstWord"
}
},
columns: [{
field: "name"
}, {
field: "firstWord",
hidden: true,
groupHeaderTemplate: "#=value#"
}]
});
This is just a fix over Ryan Hoyle answer's example:
var grid = $('#grid').kendoGrid({
dataSource: {
data: [{
name: 'Hello world'
}, {
name: 'Hello John Doe'
}, {
name: 'Hello Jane Doe'
}, {
name: 'Bye Jane Doe'
}, {
name: 'Bye World'
}],
schema: {
parse: function(data) {
data.forEach(d => d.firstWord = d.name.split(' ')[0]);
return data;
}
},
group: {
field: "firstWord"
}
},
columns: [{
field: "name"
}, {
field: "firstWord",
hidden: true,
groupHeaderTemplate: "#=value#"
}]
}).data().kendoGrid;
<link href="http://kendo.cdn.telerik.com/2016.2.607/styles/kendo.common.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.607/js/kendo.all.min.js"></script>
<div id="grid"></div>
Please see example below.
JSFiddle: http://jsfiddle.net/R7UvH/2/
How do I make typeahead.js (0.10.1) search for matches in more than one property value? Ideally, within whole data (data.title, data.desc and in all data.category[i].name)
datumTokenizer: function(data) {
// **search in other property values; e.g. data.title & data.desc etc..**
return Bloodhound.tokenizers.whitespace(data.title);
},
Whole example:
var data = [{
title: "some title here",
desc: "some option here",
category: [{
name: "category 1",
}, {
name: "categoy 2",
}]
},
{
title: "some title here",
desc: "some option here",
category: [{
name: "category 1",
}, {
name: "categoy 2",
}]
}];
var posts = new Bloodhound({
datumTokenizer: function(data) {
// **search in other property values; e.g. data.title & data.desc etc..**
return Bloodhound.tokenizers.whitespace(data.title);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data
});
posts.initialize();
$('#search-input').typeahead({
highlight: true
}, {
name: 'Pages',
displayKey: 'title',
source: posts.ttAdapter(),
templates: {
header: '<h3>Pages</h3>'
}
});
Typeahead 0.10.3 added "support to object tokenizers for multiple property tokenization."
So, your example becomes
var posts = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title', 'desc'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data
});
However, I don't think this will work for properties nested inside, that is, the data.category object in your case.
As a side note, if you are using prefetched data, be sure to clear the local storage first, otherwise the new tokenizer won't take effect (Because datumTokenizer is used when adding to the search index, and if data is already present in localStorage, then the search index will not be updated). I was stuck on this for a while!
return Bloodhound.tokenizers.whitespace(data.title) returns an array of strings.
So, instead of returning that value: save it (and your other desired values), then concatenate them and return that value...
x = Bloodhound.tokenizers.whitespace(data.title);
y = Bloodhound.tokenizers.whitespace(data.desc);
z = Bloodhound.tokenizers.whitespace(data.category[i].name);
return x.concat(y).concat(z);
I've implemented a solution here:
http://jsfiddle.net/Fresh/4nnnG/
As you have a local datasource you need to create individual datasets to enable you to match on multiple data properties. e.g.
$('#search-input').typeahead({
highlight: true
}, {
name: 'titles',
displayKey: 'title',
source: titles.ttAdapter()
}, {
name: 'descs',
displayKey: 'desc',
source: descs.ttAdapter()
}, {
name: 'cats',
displayKey: 'name',
source: cats.ttAdapter()
});