Flutter Printing Package: Create pdf table with loop - pdf

I want to create a pdf document with the package 'pdf'. The example on the dart - page is working fine: https://pub.dev/packages/pdf#-example-tab-
You can see that the table is static. I want to create a dynamic table in the pdf document.
The columns will be constant, but the rows have to be dynamic.
I have tried to insert a for() - loop.
The syntax is not correct.
pdfWidget.Table.fromTextArray(context: context, data: <List<String>> [
<String>['Date', 'PDF Version', 'Acrobat Version'],
//.....
//more Strings here.....
]),

I ran into the same issue.
This seemed to work for me.
pdf.addPage(
MultiPage(
build: (context) => [
Table.fromTextArray(context: context, data: <List<String>>[
<String>['Msg ID', 'DateTime', 'Type', 'Body'],
...msgList.map(
(msg) => [msg.counter, msg.dateTimeStamp, msg.type, msg.body])
]),
],
),
);
where my msgList object was a custom List, ie: List<SingleMessage>

There are several ways to do it, I prefer to fill the List separately, like:
List<List<String>> salidas = new List();
salidas.add(<String>['Title1','Title2', ... , 'Title n']);
for(var indice=0;indice<records.length;indice++) {
List<String> recind = <String>[
records[indice].Stringfield1,
records[indice].Stringfield2,
...,
records[indice].Stringfieldn
];
salidas.add(recind);
}
...
fpdf.Table.fromTextArray(context: context,data: salidas),

Related

Laravel Excel: how to have all zeroes printed in a exported csv?

I'm exporting to csv using Laravel Excel.
I'm creating the out value as
'amount' => number_format(-$ai->final_invoice_amount, 2, ".", "")
But, for example for 204.00, in the exported csv I got only 204, without dot and leading zeroes.
I know that it's a valid number for a computer; but our client has a strict parser and it wants a 204.00 value.
I tried, but not works, to add an explicit cast to string, but it's useless because number_format outputs a string in any case
'amount' => (string)number_format(-$ai->final_invoice_amount, 2, ".", "")
Laravel Excel's Events give you access to PHPSpreadSheet under the hood.
https://docs.laravel-excel.com/3.1/exports/extending.html#events
With Events, you can apply the desired formatting to a cell or group of cells. It's easier to demonstrate than explain, so I have created a simple example.
<?php
namespace App\Export;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeSheet;
class SampleExport implements FromCollection, WithEvents
{
public function collection()
{
return collect([
[
'id' => 1,
'amount_1' => 100,
'amount_2' => 75.20,
'amount_3' => -23.10,
],
[
'id' => 2,
'amount_1' => -60,
'amount_2' => 50.40,
'amount_3' => 110,
],
]);
}
public function registerEvents(): array
{
return [
BeforeSheet::class => function (BeforeSheet $event) {
// format columns B-D to two decimal places
$event->sheet
->getDelegate()
->getStyle('B:D')
->getNumberFormat()
->setFormatCode('0.00');
},
];
}
}
This is the resulting CSV as output to a file.
"1","100.00","75.20","-23.10"
"2","-60.00","50.40","110.00"
NOTE: The values being formatted MUST BE A NUMBER TYPE! Attempting to format strings will not work.

Sequelize raw query update array of objects as replacements

I am using sequelize (postgres) and I need to properly escape a query like this:
`
UPDATE "Pets"
SET "name" = CASE LOWER("name")
${input.pets
.map((pet) => `WHEN '${pet.name.toLowerCase()}' THEN '${pet.newName}'`)
.join('\n')}
ELSE "name"
END
WHERE LOWER("name") IN(${input.pets
.map((pet) => `'${pet.name.toLowerCase()}'`)
.join(',')});
`
Sample input.pets:
[{ name: "rocky", newName: "leo" }]
Does anyone have an idea how to achieve this with replacements?
I have found a thread on github which suggested something like this:
let data = [ [ 252456, 1, 55, '0' ],
[ 357083, 1, 56, '0' ],
[ 316493, 1, 57, '0' ] ];
db.query(
`INSERT INTO product (a, b) VALUES ${data.map(a => '(?)').join(',')};`,
{
replacements: data,
type: Sequelize.QueryTypes.INSERT
}
);
However, a 2d array is being used here not an array of objects. Is there a way to access individual properties from the array? When I try something like this
`
UPDATE "Pets"
SET "name" = CASE LOWER("name")
${input.pets
.map((_pet) => `WHEN ? THEN ?`)
.join('\n')}
ELSE "name"
END
WHERE LOWER("name") IN(${input.pets
.map((_pet) => `?`)
.join(',')});
`,
{ type: QueryTypes.UPDATE, replacements: input.pets },
The first ? turns out to be the whole object. Is there a way to access it's properties?
I also tried transforming input.pets into a 2d array but still couldn't get it to work as in example with insert above.
In advance thanks for your time
const names = input.pets.map((pet) => pet.name);
const newNames = input.pets.map((pet) => pet.newName);
`
UPDATE "Pets"
SET "name" = CASE LOWER("name")
${names.map((_) => `WHEN LOWER(:names) THEN :newNames`).join('\n')}
ELSE "name"
END
WHERE LOWER("name") IN(${names.map((_) => `LOWER(:names)`).join(',')});
`,
{ replacements: { names, newNames } },
This works. In cases like this it's better to work with simpler data structures. Another option I found is using sequelize.escape() built-in function, but it's not documented so I decided not to
EDIT:
After some testing, this works but for only one object in the input
If the input looks something like this:
[
{ name: "rocky", newName: "fafik" }
{ name: "asd", newName: "qwerty" }
]
Then in resut I get queries like this:
WHEN LOWER('rocky', 'asd') THEN 'fafik', 'qwerty'
WHEN LOWER('rocky', 'asd') THEN 'fafik', 'qwerty'
So it doesn't loop over arrays. Still the problem remains, how to access individual properties, whether from array or an object?
EDIT2: FINAL ANSWER
sequelize.query(
`
UPDATE "Pets"
SET "name" = CASE LOWER("name")
${input.pets.map(() => `WHEN ? THEN ?`).join('\n')}
ELSE "name"
END
WHERE LOWER("name") IN(?);
`,
{
replacements: [
...input.pets.flatMap((x) => [x.name.toLocaleLowerCase(), x.newName]),
input.pets.map((x) => x.name.toLocaleLowerCase()),
],
},

Ramda.js - how to view many values from a nested array

I have this code:
import {compose, view, lensProp, lensIndex, over, map} from "rambda";
let order = {
lineItems:[
{name:"A", total:33},
{name:"B", total:123},
{name:"C", total:777},
]
};
let lineItems = lensProp("lineItems");
let firstLineItem = lensIndex(0);
let total = lensProp("total");
My goal is to get all the totals of all the lineItems (because I want to sum them). I approached the problem incrementally like this:
console.log(view(lineItems, order)); // -> the entire lineItems array
console.log(view(compose(lineItems, firstLineItem), order)); // -> { name: 'A', total: 33 }
console.log(view(compose(lineItems, firstLineItem, total), order)); // -> 33
But I can't figure out the right expression to get back the array of totals
console.log(view(?????, order)); // -> [33,123,777]
That is my question - what goes where the ????? is?
I coded around my ignorance by doing this:
let collector = [];
function collect(t) {
collector.push(t);
}
over(lineItems, map(over(total, collect)), order);
console.log(collector); // -> [33,123,777]
But I'm sure a ramda-native knows how to do this better.
It is possible to achieve this using lenses (traversals), though will likely not be worth the additional complexity.
The idea is that we can use R.traverse with the applicative instance of a Const type as something that is composable with a lens and combines zero or more targets together.
The Const type allows you to wrap up a value that does not change when mapped over (i.e. it remains constant). How do we combine two constant values together to support the applicative ap? We require that the constant values have a monoid instance, meaning they are values that can be combined together and have some value representing an empty instance (e.g. two lists can be concatenated with the empty list being the empty instance, two numbers can be added with zero being the empty instace, etc.)
const Const = x => ({
value: x,
map: function (_) { return this },
ap: other => Const(x.concat(other.value))
})
Next we can create a function that will let us combine the lens targets in different ways, depending on the provided function that wraps the target values in some monoid instance.
const foldMapOf = (theLens, toMonoid) => thing =>
theLens(compose(Const, toMonoid))(thing).value
This function will be used like R.view and R.over, accepting a lens as its first argument and then a function for wrapping the target in an instance of the monoid that will combine the values together. Finally it accepts the thing that you want to drill into with the lens.
Next we'll create a simple helper function that can be used to create our traversal, capturing the monoid type that will be used to aggregate the final target.
const aggregate = empty => traverse(_ => Const(empty))
This is an unfortunate leak where we need to know how the end result will aggregated when composing the traversal, rather than simply knowing that it is something that needs to be traversed. Other languages can make use of static types to infer this information, but no such luck with JS without changing how lenses are defined in Ramda.
Given you mentioned that you would like to sum the targets together, we can create a monoid instance that does exactly that.
const Sum = x => ({
value: x,
concat: other => Sum(x + other.value)
})
This just says that you can wrap two numbers together and when combined, they will produce a new Sum containing the value of adding them together.
We now have everything we need to combine it all together.
const sumItemTotals = order => foldMapOf(
compose(
lensProp('lineItems'),
aggregate(Sum(0)),
lensProp('total')
),
Sum
)(order).value
sumItemTotals({
lineItems: [
{ name: "A", total: 33 },
{ name: "B", total: 123 },
{ name: "C", total: 777 }
]
}) //=> 933
If you just wanted to extract a list instead of summing them directly, we could use the monoid instance for lists instead (e.g. [].concat).
const itemTotals = foldMapOf(
compose(
lensProp('lineItems'),
aggregate([]),
lensProp('total')
),
x => [x]
)
itemTotals({
lineItems: [
{ name: "A", total: 33 },
{ name: "B", total: 123 },
{ name: "C", total: 777 }
]
}) //=> [33, 123, 777]
Based on your comments on the answer from customcommander, I think you can write this fairly simply. I don't know how you receive your schema, but if you can turn the pathway to your lineItems node into an array of strings, then you can write a fairly simple function:
const lineItemTotal = compose (sum, pluck ('total'), path)
let order = {
path: {
to: {
lineItems: [
{name: "A", total: 33},
{name: "B", total: 123},
{name: "C", total: 777},
]
}
}
}
console .log (
lineItemTotal (['path', 'to', 'lineItems'], order)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {compose, sum, pluck, path} = R </script>
You can wrap curry around this and call the resulting function with lineItemTotal (['path', 'to', 'lineItems']) (order), potentially saving the intermediate function for reuse.
Is there a particular reason why you want to use lenses here? Don't get me wrong; lenses are nice but they don't seem to add much value in your case.
Ultimately this is what you try to accomplish (as far as I can tell):
map(prop('total'), order.lineItems)
you can refactor this a little bit with:
const get_total = compose(map(prop('total')), propOr([], 'lineItems'));
get_total(order);
You can use R.pluck to get an array of values from an array of objects:
const order = {"lineItems":[{"name":"A","total":33},{"name":"B","total":123},{"name":"C","total":777}]};
const result = R.pluck('total', order.lineItems);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

Delete and add attributes with array.map and the spread operator

I'm trying to mangle data returned from an api. I've got an array of objects returned. I want to delete the password field and then add a couple of additional fields. I'd like to use the spread operator but my process feels a bit clunky.
myArray.map( item => {
const newItem = { ...item };
delete newItem.password;
newItem.saved = true;
return newItem;
});
Is there a nicer way to do this?
Given an array of objects -
const myArrayOfObjects = [
{id: 1, keyToDelete: 'nonsense'},
{id: 2, keyToDelete: 'rubbish'}
];
Delete the attribute keyToDelete, and add a new key newKey with the value "someVar".
myArrayOfObjects.map(({ keyToDelete, ...item}) => { ...item, newKey:'someVar'});
Updating the array to
[
{id: 1, newKey:'someVar'},
{id: 2, newKey:'someVar'}
]
See this great post for more information on the deletion method.

Dojo DGrid RQL Search

I am working with a dgrid where I want to find a search term in my grid on two columns.
For instance, I want to see if the scientific name and commonName columns contain the string "Aca" (I want my search to be case insensitive)
My Grid definition:
var CustomGrid = declare([Grid, Pagination ]);
var gridStore = new Memory({ idProperty: 'tsn', data: null });
gridStore.queryEngine = rql.query;
grid = new CustomGrid({
store: gridStore,
columns:
[
{ field: "tsn", label: "TSN #"},
{ field: "scientificName", label: "Scientific Name"},
{ field: "commonName", label: "Common Name",},
],
autoHeight: 'true',
firstLastArrows: 'true',
pageSizeOptions: [50, 100],
}, id);
With the built in query language (I think simple query language), I was able to find the term in one column or the other, but I couldn't do a complex search that would return results for both columns.
grid.set("query", { scientificName : new RegExp(speciesKeyword, "i") });
grid.refresh()
I started reading and I think RQL can solve this problem, however, I am struggling with the syntax.
I have been looking at these pages:
http://rql-engine.eu01.aws.af.cm/
https://github.com/kriszyp/rql
And I am able to understand basic queries, however the "contains" syntax eludes me.
For instance if I had this simple data set and wanted to find the entries with scientific and common names that contain the string "Aca" I would think my contains query would look like this:
contains(scientificName,string:aca)
However, this results in no matches.
[
{
"tsn": 1,
"scientificName": "Acalypha ostryifolia",
"commonName": "Rough-pod Copperleaf",
},
{
"tsn": 2,
"scientificName": "Aegalius acadicus",
"commonName": "Northern Saw-whet Owl",
},
{
"tsn": 3,
"scientificName": "Portulaca pilosa",
"commonName": "2012-02-01",
},
{
"tsn": 4,
"scientificName": "Accipiter striatus",
"commonName": "Kiss-me-quick",
},
{
"tsn": 5,
"scientificName": "Acorus americanus",
"commonName": "American Sweetflag",
}
]
Can someone guide me in how to formulate the correct syntax? Thank you.
From what I'm briefly reading, it appears that:
contains was replaced by any and all
these are meant for array comparisons, not string comparisons
I'm not sure offhand whether RegExps can just be handed to other operations e.g. eq.
With dojo/store/Memory, you can also pass a query function which will allow you to do whatever you want, so if you wanted to compare for a match in one field or the other you could do something like this:
grid.set('query', function (item) {
var scientificRx = new RegExp(speciesKeyword, 'i');
var commonRx = new RegExp(...);
return scientificRx.test(item.scientificName) || commonRx.test(item.commonName);
});
Of course, if you want to filter only items that match both, you can do that with simple object syntax:
grid.set('query', {
scientificName: scientificRx,
commonName: commonRx
});