Summing a column in a table in Meteor - meteor

If I create a table in a Template, is there a way to add a row of "reactive totals" at the bottom of the table using Meteor? Or do I have to write the code to sum the columns, the same way I would in ordinary JavaScript?
For example, given the table...
State Sales
NY 1234
FL 670
TX 2306
Total 4210
Can I use some reactive technique to calculate and keep the Total cell showing 4210 up-to-date as other cells change?

Another way to do this is to use MongoDB $sum aggregator
Taking Erik Johnson's example, you need to do this:
// HTML
<div id="allSales">
<h2><span>Total sales: </span>{{allSales}}</h2>
</div>
// JS
Template.templatename.helpers({
allSales: function() {
var allSales = allStates.aggregate( [ { $group: { _id: null, total: { $sum: "$sales" } } } ]);
return allSales.total;
},
});

This is how I've done it - I'm sure there's probably an easier way, but I'm still a beginner at Meteor:
// HTML
<div id="allSales">
<h2><span>Total sales: </span>{{allSales}}</h2>
</div>
// JS
Template.templatename.helpers({
allSales: function() {
var allStates = Statescollection.find();
var mappedItems = allStates.map((function(allStates) {return allStates.sales;}));
var allSales = _.reduce(mappedItems, function(memo, num){ return memo + num; }, 0);
return allSales;
},
});

I've created the package peppelg:mongo-sum. With it, MyCollection.find().sum('field') will return the sum of all the values in the field 'field'.

I had the same issue, and have found the following solution for both columns and rows of a table
In Meteor, how can i do a sum of some computed fields in a table?

Related

Has column show property stopped working in latest react-table v7?

I have used the show property to show/hide columns in my table earlier and it has worked fine using react-table v7. However, recently I cannot get it to work any longer, since I've made a bunch of changes and my table is quite complex I'm not sure what caused it, possibly also an update of react-table itself (7.0.0-beta.12 to 7.0.0-rc.5).
Anyway, now I can't even get the most basic show example to work:
const columns = React.useMemo(
() => [
{
Header: "Info",
columns: [
{
Header: "Age",
accessor: "age",
show: false
},
{
Header: "Visits",
accessor: "visits"
}
]
}
],
[]);
https://codesandbox.io/s/react-table-hide-column-2g3js
Why is the 'age' column showing?
Edit
Digging into the changelog I now understand that column show/hide has indeed changed:
7.0.0-beta.28 Added the useColumnVisibility plugin as a core plugin along with several new instance and column-level methods to control
column visibility Added the "column-hiding" example
However, I still have not figured out how to apply the useColumnVisibility hook to a column in a similar way to how show used to work. The "column-hiding" example shows how to do it with checkboxes but does not help in my case (afaik).
I had a similar issue as I was using show. Instead of setting show in the column, set the initialState.hiddenColumns, here you can convert your existing show into the initial hidden columns:
useTable<T>(
{
columns,
data,
hiddenColumns: columns.filter(column => !column.show).map(column => column.id)
},
I couldn't use that as my columns are loaded dynamically (so the initial state was set to some columns that didn't exist, and was just set to an empty array) so I used:
React.useEffect(
() => {
setHiddenColumns(
columns.filter(column => !column.show).map(column => column.id)
);
},
[columns]
);
where setHiddenColumns is provided by useTable:
const {
headerGroups,
rows,
prepareRow,
state,
toggleRowSelected,
toggleAllRowsSelected,
setHiddenColumns
} = useTable<T>(
{
columns,
data,
getRowId,
...
This means if I changed the column props it would be reflected in the table.
I also use setHiddenColumns to show/hide columns. However, instead returning Header, I use id. My code:
...
setHiddenColumns,
flatColumns,
headerGroups,
state: { pageIndex, pageSize },
} = useTable({
columns,
data,
initialState: { pageIndex: 0 },
manualPagination: true,
pageCount: controlledPageCount,
},
useSortBy,
usePagination
);
React.useEffect(() => {
const hiddenColumns = flatColumns.filter((column: any) => !column.show).map((column: any)=> column.id);
setHiddenColumns(hiddenColumns); }, []);

Vue/Vuex watcher dynamic/async component loading

I have a base component within which I have a dynamic component with a v-for that displays based on a computed property.
All I've really tried doing thus far, which was an incorrect methodology, was to wrap the method that loads data in a settimeout. This question is as much a methodology question as it is a coding question.
My base component looks like this:
<template>
<div>
<v-progress-linear
v-model="progressValue"
v-if="loading"
></v-progress-linear>
<component
v-for="table in tables"
:key="table.id"
:is="table.structure"
:table="table"
></component>
</div>
</template>
<script>
import Annual from './DataTables/Annual';
import { mapState, mapGetters } from 'vuex';
export default {
name: "Page",
props: [],
components: {
Annual,
},
data: () => ({
progressValue: 0,
loading: false,
tables: [],
}),
computed: {
...mapGetters({
currentTables: 'getCurrentPageTables',
tableTitles: 'getCurrentPageTableTitles',
}),
...mapState({
pageName: state => state.pageName,
snakeName: state => state.snakeName,
}),
methods: {
updateTables(payload) {
this.loading = true;
payload.forEach(title => {
this.tables.push(this.currentTables.filter(e => title === e.name)[0]);
this.progressValue = this.tables.length / payload.length;
})
},
},
watch: {
snakeName: {
handler() {
this.progressValue = 0;
this.updateTables(this.tableTitles);
this.$nextTick(() => {this.loading = false;})
},
immediate: true,
},
}
}
</script>
Annual.vue is simply a component that displays a Vuetify v-data-table element and its structure is fairly inconsequential to this.
For all intents and purposes we can consider currentTables and tableTitles to both be arrays, the first of objects whose data populate the v-data-tables in Annual.vue, and the second of strings which are just the names of the tables.
When the user navigates to another page the getters return different data, based on the page the user navigates to, but some of the pages have over 20 tables, which makes page loading slow upon navigation to these pages. I am trying to do one of two things:
1. Asynchronously load the components one at a time while still making the page functional for the user to navigate through.
2. Display a loader that disappears after all of the content is rendered. I'm having trouble figuring out how to do the latter because I can't put this functionality into the mounted() hook since all of this happens upon the watched parameter changing (hence the component is not re-mounted each time the route changes).
Any advice on how to tackle this would be appreciated.

With an express app, how to use my schema data in css/stylus?

I'm trying to create a themes for my express app and i'm trying to do something that i'm not sure is possible. I need some expert advice on ways or methods to do this.
This is my schema...
var colorSchema = new Schema({
primaryColor: {
type: String
},
secondaryColor: {
type: String
}
});
module.exports = mongoose.model('Color', colorSchema);
Let's say i've entered hex colors into primaryColor and secondaryColor when I create a new schema. How can I parse color.primaryColor as a value in my css or stylus like you do in jade?
Be sure to first pass the data to Jade through render in Express:
// Default both to white
res.render('template_name', {
primaryColor: color.primaryColor || '#FFF',
secondaryColor: color.secondaryColor || '#FFF',
someOtherVar: 'foo'
});
Then, in your Jade template:
style(type='text/css')
| .primary-color-bg { background-color: #{primaryColor}; }
| .secondary-color-bg { background-color: #{secondaryColor}; }
You can then apply primary-color-bg and secondary-color-bg classes to any DOM elements you want to set the background of. You can replicate for color, border, etc. attributes.
Stylus actually has a JavaScript API that allows you to render even arbitrary strings of Stylus code.
stylus = require('stylus');
variable = '#fff';
stylus.render(
"\n.thing" +
"\n color: " + variable + "\n",
console.log);
This is a pretty dumb example, but it gets the point of freedom you have. That API also allows for more "composable" compile-function definition, that lets you expose JS values (via .define) into Stylus.
stylus(str)
.set('filename', 'nesting.css')
.define('whatever', '#fff')
.render(console.log);

Meteor C3 charts based on D3 - multiple charts?

EDIT: clone this repository for a non working reproduction. https://github.com/FickleLife/meteor-c3-test
I am using https://github.com/peernohell/meteor-c3.js/
I pull two examples off the C3 site http://c3js.org/examples.html and can get them to display once on the page, but when I try to add a second on the same page the first disappears. There's no console error and the javascript variables are different.
chart 1 html template:
<template name="chart_cp_overview">
<div id="cpOverview"></div>
</template>
chart 1 js helper:
Template.chart_cp_overview.rendered = function () {
var cpOverview = c3.generate({
data: {
columns: [
['data1', 30, 200],
['data2', 130, 100]
],
type: 'bar',
groups: [
['data1', 'data2']
]
},
grid: {
y: {
lines: [{value:0}]
}
}
});
}
chart 2 html template:
<template name="chart_status">
<div id="chart"></div>
</template>
chart 2 helper:
Template.chart_status.rendered = function() {
var chart = c3.generate({
data: {
columns: [
['Dropped', 30],
['On Course', 120],
['DNS', 20],
['Finished', 40]
],
colors: {
'Dropped': '#E60000',
'On Course': '#00ACED',
'DNS': '#DBDBDB',
'Finished': '#00BD07'
},
type : 'donut',
onclick: function (d, i) { console.log("onclick", d, i); }
// onmouseover: function (d, i) { console.log("onmouseover", d, i); },
// onmouseout: function (d, i) { console.log("onmouseout", d, i); }
},
donut: {
title: "Entrant Status",
label: {
format: function (value, ratio) {
return value;
}
}
}
});
};
display code :
<div class="row">
<div class="col-md-6">
{{> chart_cp_overview}}
</div>
<div class="col-md-6">
{{> chart_status}}
</div>
</div>
This code above displays only the last chart - chart_status. If I remove any one of the handlebars reference the other chart displays fine, or if I have multiple handlebars to multiple charts whatever was last declared is displayed.
How can I get multiple charts to display within one page? Example is on github at https://github.com/FickleLife/meteor-c3-test
It looks like maybe you are intending the two variable names you have chosen in your template rendered functions, cpOverview and chart, to bind to the dom elements with those ids. It won't work that way.
The variable names you have chosen are local to their functions and in any case would not automatically attach to elements with that id even if they were global. So c3 is binding all these charts to the same dom element (the docs say the default is #chart), and the last one is overriding the prior ones.
You want to bind each chart to its respective element. You can use this.firstNode inside your rendered function (based on the way you have it set up), or use jquery, or this.find("div#cpOverview"), and then use the c3 api to bind the chart to it - it looks like { bindto: "div#cpOverview" } may be the one you want.

ExtJS 4 / 5 - Set the correct CSS for a Drag and Drop that is not allowed with custom rules

I have two grids side by side.
The left grid has a list of tags the user can select, and the grid on the right is empty so the user can drag the tags he wants there.
The plugin code for both grids is:
viewConfig: {
plugins: [
Ext.create('Ext.grid.plugin.DragDrop', {
ddGroup: 'selectedTags'
})
]
}
So, as I wanted to limit the user to be able to drag only 5 tags, I've added the following code to the grid on the right:
listeners: {
beforedrop: {
fn: function() {
if (grid.getStore().data.items.length > 4) {
dropHandlers.cancelDrop();
}
},
scope: me
}
}
This is working perfectly but what I wanted is to show the NO-DROP icon when the items are dragged over the grid instead of showing the green line as if the action was allowed.
Thanks,
After looking for this solution for a while, I finally figured it out.
You must add two methods to the dropZone in the Target Grid:
notifyOver and onNodeDrop
The solution for my problem would be the code below:
Ext.create('Ext.grid.Panel', {
store: myStore,
columns: [columns],
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
pluginId : 'dragNdrop',
dropZone:{
notifyOver:function(source, e, data){
var store = this.view.ownerCt.getStore();
return store.getCount()<5?this.dropAllowed:this.dropNotAllowed
},
onNodeDrop:function(targetNode,dragZone,e,data){
var sourceStore = dragZone.view.ownerCt.getStore(),
targetStore = this.view.ownerCt.getStore(),
isDropValid = targetStore.getCount()<5;
if(isDropValid){
sourceStore.remove(data.records[0])
targetStore.add(data.records[0]);
}
return isDropValid;
}
}
}
},
height: 200,
width: 400,
renderTo: Ext.getBody()
});
Lopes, you can use column renderer in grid where you can check the items count and display appropriate icon. Code snippet for your reference:
gridCheckboxRenderer: function(value, meta, rec, rowInd, colInd, store){
var cssPrefix = Ext.baseCSSPrefix, cls = [cssPrefix + 'grid-checkheader'];
if (condition == false) {
cls.push(cssPrefix + 'grid-checkheader-checked-disabled');
return '<div class="' + cls.join(' ') + '"> </div>';
}
return '<div class="x-grid-row-checker"> </div>';
}
Hope it helps.

Resources