I tried to count num of rows in grid in runtime with this code
FormRun caller;
FormDataSource fds;
QueryRun queryRun;
int64 rows;
fds = caller.dataSource();
query = fds.query();
queryRun = new QueryRun(query);
rows = SysQuery::countTotal(queryRun); //this returns -1587322268
rows = SysQuery::countLoops(queryRun); //this returs 54057
The last line of code is closest to what i need because there are 54057 lines but if i add filters it still returns 54057.
I want logic to get the number rows that grid has in the moment of calling the method.
Your query has more than one datasource.
The best way to explain your observation is to look at the implementation of countTotal and countLoops.
public client server static Integer countTotal(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,1);
}
public client server static Integer countLoops(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,2);
}
private server static container countPrim(container _queryPack)
{
...
if (countQuery.dataSourceCount() == 1)
qbds.addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
countQueryRun = new QueryRun(countQuery);
while (countQueryRun.next())
{
common = countQueryRun.get(countQuery.dataSourceNo(1).table());
counter += common.RecId;
loops++;
}
return [counter,loops];
}
If your datasource contains one datasource it adds count(RecId).
countTotal returns the number of records.
countLoops returns 1.
Pretty fast, as fast as the SQL allows.
If your datasource contains more than one datasource it does not add count(RecId).
countTotal returns the sum of recIds (makes no sense).
countLoops returns the number of records.
Also countLoops is slow if there are many records as they are counted one by one.
If you have two datasources and want a fast count, you are on your own:
fds = caller.dataSource();
queryRun = new QueryRun(fds.queryRun().query());
queryRun.query().dataSourceNo(2).joinMode(JoinMode::ExistsJoin);
queryRun.query().dataSourceNo(1).clearFields();
queryRun.query().dataSourceNo(1).addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
queryRun.next();
rows = queryRun.getNo(1).RecId;
The reason your count did not respect the filters was because you used datasource.query() rather than datasource.queryRun().query(). The former is the static query, the latter is the dynamic query with user filters included.
Update, found some old code with a more general approach:
static int tableCount(QueryRun _qr)
{
QueryRun qr;
Query q = new Query(_qr.query());
int dsN = _qr.query().dataSourceCount();
int ds;
for (ds = 2; ds <= dsN; ++ds)
{
if (q.dataSourceNo(ds).joinMode() == JoinMode::OuterJoin)
q.dataSourceNo(ds).enabled(false);
else if (q.dataSourceNo(ds).joinMode() == JoinMode::InnerJoin)
{
q.dataSourceNo(ds).joinMode(JoinMode::ExistsJoin);
q.dataSourceNo(ds).fields().clearFieldList();
}
}
q.dataSourceNo(1).fields().clearFieldList();
q.dataSourceNo(1).addSelectionField(fieldNum(Common,RecId), SelectionField::Count);
qr = new QueryRun(q);
qr.next();
return any2int(qr.getNo(1).RecId);
}
I want to update some data in the forms of
wordBank = {
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
}
the goal is to able to extract and display all the values of all the keys in each JSON object. How do I create this format on firebase? do I use .update? or something else?
currently I could only get firebase .update() to work with an array but it gives me data like this
wordBank = [
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
];
where each word-object is an index in the array.
Here's how I construct my wordObjects:
function getWords() {
if (document.getElementsByClassName("vortarobobelo").length != 0){
var words;
words = document.getElementsByClassName("vortarobobelo")[0].children[0].children;
for (var i =0; i < words.length; i++) {
var localBank = {} //creating the local variable to store the word
var newWord = words[i].children[0].innerText; // getting the word from the DOM
var newTranslation = words[i].children[1].innerText; // getting the translation from the DOM
localBank.word = newWord;
localBank.translation = newTranslation;
localBank.count = 0 //assuming this is the first time the user has clicked on the word
console.log(localBank);
wordBank[localBank.word] = localBank;
fireBank.update(localBank);
}
}
}
If you want to store the items within an object, you need to pick keys to store them against.
You can't store unkeyed values inside an object in Javascript. This would result in a syntax error:
wordBank = {
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
}
The other option is to store them in an array, in which case the keys will be automatically assigned as array indices. Just like your second example.
Maybe you want to store the word objects, using the word itself as a key?
wordBank = {
aprobi: {word:"aprobi", translation:"to approve", count:2},
bati: {word:"bati", translation:"to hit, to beat, to strike", count:1},
da: {word:"da", translation:"of", count:1}
}
This would be easy to do with Firebase. Let's say you have all of your word objects as a list.
var ref = new Firebase("your-firebase-url");
wordObjects.forEach(function(wordObject) {
ref.child(wordObject.word).set(wordObject);
});
Or you could create the object with Javascript, then add it to Firebase using .update.
var wordMap = {};
wordObjects.forEach(function(wordObject) {
wordMap[wordObject.word] = wordObject;
});
ref.update(wordMap);
Coming from a Java background: what is the recommended way to "clone" a Dart List, Map and Set?
Use of clone() in Java is tricky and questionable1,2. Effectively, clone() is a copy constructor and for that, the Dart List, Map and Set types each have a named constructor named .from() that perform a shallow copy; e.g. given these declarations
Map<String, int> numMoons, moreMoons;
numMoons = const <String,int>{ 'Mars' : 2, 'Jupiter' : 27 };
List<String> planets, morePlanets;
you can use .from() like this:
moreMoons = new Map<String,int>.from(numMoons)
..addAll({'Saturn' : 53 });
planets = new List<String>.from(numMoons.keys);
morePlanets = new List<String>.from(planets)
..add('Pluto');
Note that List.from() more generally accepts an iterator rather than just a List.
For sake of completeness, I should mention that the dart:html Node class defines a clone() method.
1 J. Bloch, "Effective Java" 2nd Ed., Item 11.
2 B. Venners, "Josh Bloch on Design: Copy Constructor versus Cloning", 2002. Referenced from here3. Quote from the article:
If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. ---J.Bloch
3 Dart Issue #6459, clone instance(object).
With the new version of dart cloning of a Map or List become quite easy.
You can try this method for making a deep clone of List and Map.
For List
List a = ['x','y', 'z'];
List b = [...a];
For Maps
Map mapA = {"a":"b"};
Map mapB = {...mapA};
For Sets
Set setA = {1,2,3,};
Set setB = {...setA};
I hope someone find this helpful.
If you are using dart > 2.3.0, You can use spread operator something like:
List<int> a = [1,2,3];
List<int> b = [...a]; // copy of a
For lists and sets, I typically use
List<String> clone = []..addAll(originalList);
The caveat, as #kzhdev mentions, is that addAll() and from()
[Do] not really make a clone. They add a reference in the new Map/List/Set.
That's usually ok with me, but I would keep it in mind.
For deep copy (clone), you can use :
Map<String, dynamic> src = {'a': 123, 'b': 456};
Map<String, dynamic> copy = json.decode(json.encode(src));
but there may be some concerns about the performance.
This solution should work:
List list1 = [1,2,3,4];
List list2 = list1.map((element)=>element).toList();
It's for a list but should work the same for a map etc, remember to add to list if its a list at the end
Map.from() only works for 1D map.
To copy multi dimensional map without reference in dart use following method
Map<keyType, valueType> copyDeepMap( Map<keyType, valueType> map )
{
Map<keyType, valueType> newMap = {};
map.forEach
(
(key, value)
{
newMap[key] =( value is Map ) ? copyDeepMap(value) : value ;
}
);
return newMap;
}
Method-1: Recommended
For cloning a multi-dimensional (nested) List or Map, use the
json.decode() and json.encode()
List newList = json.decode(json.encode(oldList));
Map newMap = json.decode(json.encode(oldList));
Method-2:
List newList = [...oldList];
Map newMap = {...oldMap}
Method-3:
List newList = List.from(oldList);
Map newMap = Map.from(oldMap);
Method-4:
List newList = List.of(oldList);
Map newMap = Map.of(oldMap);
Method-5:
List newList = List.unmodifiable(oldList);
Map newMap = Map.unmodifiable(oldMap);
For more References:
https://www.kindacode.com/article/how-to-clone-a-list-or-map-in-dart-and-flutter/
https://coflutter.com/dart-flutter-how-to-clone-copy-a-list/
Best solution for me:
List temp = {1,2,3,4}
List platforms = json.decode(json.encode(parent.platforms));
This was my solution. I hope it can help someone.
factory Product.deepCopy(Product productToCopy) => new Product(
productToCopy.id,
productToCopy.title,
productToCopy.description,
productToCopy.price,
productToCopy.imageUrl,
productToCopy.isFavorite,
);}
To copy Map<String, List> filtered;
var filteredNewCopy = filtered.map((key, value) => MapEntry(key, [...value]));
There is no 100% bullet proof way of making an exact isolated copy, but the answer from Manish Dhruw is pretty good. However, it will only work for Maps containing simple variable types and nested Maps.
To extend it to also work with other common collections, such as List and Set, and combinations of them, you could use something like the code below.
You don't really need the DeepCopyable class, but it would be useful if you want to easily make your own classes "deep-copyable" with these functions.
abstract class DeepCopyable{
T deepCopy<T>();
}
List<T> listDeepCopy<T>(List list){
List<T> newList = List<T>();
list.forEach((value) {
newList.add(
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value
);
});
return newList;
}
Set<T> setDeepCopy<T>(Set s){
Set<T> newSet = Set<T>();
s.forEach((value) {
newSet.add(
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value
);
});
return newSet;
}
Map<K,V> mapDeepCopy<K,V>(Map<K,V> map){
Map<K,V> newMap = Map<K,V>();
map.forEach((key, value){
newMap[key] =
value is Map ? mapDeepCopy(value) :
value is List ? listDeepCopy(value) :
value is Set ? setDeepCopy(value) :
value is DeepCopyable ? value.deepCopy() :
value;
});
return newMap;
}
As I mentioned, it's obviously still not 100% bullet proof - for example you will loose type information for nested collections.
List<int> a = [1,2,3];
List<int> b = a.toList(); // copy of a
Seems to work too
**Dart 2.15
This was my solution,hope it works for you
class Person {
String? name;
int? age;
Person(this.name, this.age);
factory Person.clone(Person source) {
return Person(source.name, source.age);
}
}
final personList = [
Person('Tom', 22),
Person('Jane', 25),
];
final yourCopy = personList.map((p) => Person.clone(p)).toList();
If you are working with dynamic typed data (aka sourced from JSON or built to encode as JSON) you can use this function to perform a deep copy:
cloneDeep(value) {
if (value is List<dynamic>) {
return value.map<dynamic>(
(item) => cloneDeep(item),
).toList();
} else if (value is Map) {
return value.map<String, dynamic>(
(key, item) => MapEntry<String, dynamic>(key, cloneDeep(item)));
}
return value;
}
final list = [[],[]];
final cloned = list.copyRange(0, list.length-1);
best solution is use of toMap() and fromMap() for classes.
class A {
String title;
A(Map<String, Object> map){ // fromMap() or fromJson()
title= map['title'];
}
Map<String, Object> toMap(){
final res = <String, Object>{};
res['title'] = title;
return res;
}
}
The given answer is good, but be aware of the generate constructor which is helpful if you want to "grow" a fixed length list, e.g.:
List<String> list = new List<String>(5);
int depth = 0; // a variable to track what index we're using
...
depth++;
if (list.length <= depth) {
list = new List<String>.generate(depth * 2,
(int index) => index < depth ? list[index] : null,
growable: false);
}
I've looked at this other question, but can't get my select box to work correctly:
Binding initial/default value of dropdown (select) list
I've got the following Game object:
function Game(visitingTeamDetails, homeTeamDetails, game) {
if (arguments.length > 0) {
this.VisitingTeamDetails = visitingTeamDetails;
this.HomeTeamDetails = homeTeamDetails;
this.GameId = ko.observable(game.GameId);
this.HomeTeamName = ko.observable(game.HomeTeamName);
this.VisitingTeamName = ko.observable(game.VisitingTeamName);
this.SportTypeName = ko.observable(game.SportTypeName);
this.HomeAccountName = ko.observable(game.HomeAccountName);
this.VisitingAccountName = ko.observable(game.VisitingAccountName);
this.GameDateString = ko.observable(game.GameDateString);
this.GameTimeString = ko.observable(game.GameTimeString);
this.AvailableSportTypes = ko.observableArray(game.Sports);
this.sportTypeFunction = function () {
for (sportType in this.AvailableSportTypes()) {
if (this.AvailableSportTypes()[sportType].Name == this.SportTypeName()) {
return this.AvailableSportTypes()[sportType];
}
}
return null;
};
this.SportType = ko.observable(game.SportType);
}
}
SportType is an object with Name and SportTypeId.
I have the following template:
<td rowspan="3"><select data-bind="options: AvailableSportTypes, value: SportType, optionsText:'Name', optionsCaption: 'Choose...'" class="sportType"></select></td>
AvailableSportTypes is a list of SportType.
The list is coming in with the names of the SportTypes in the drop down list, but I can't make the initial selection be SportType. I wrote sportTypeFunction to show myself that the data was coming in correctly, and it would select the correct value, but changing my selection in the drop down would not update SportType.
I'm sure I'm doing something wrong. Anyone see it?
Thanks
When game.SportType gets passed in, it needs to be a reference to the an item in the game.AvailableSportTypes and not just an object that looks the same.
Basically two objects are not equal unless they are actually a reference to the same object.
var a = { name: "test" },
b = { name: "test" };
alert(a === b); //false
So, you would need to call your function to locate the correct object in the array and set it as the value of your observable.
Not that it is way better, but in KO 1.3 you can extend .fn of observables, observableArrays, and dependentObservables to add additional functionality.
Here is a sample: http://jsfiddle.net/rniemeyer/ZP79w
I have the code below where I am trying to go through the child questions of my qestAires anonymous type. When I get to the foreach loop i get the error:
foreach statement cannot operate on
variables of type 'Question' because
'Question' does not contain a public
definition for 'GetEnumerator'
What do I need to do differently to get around this?
var questAires = (from qs in dc.Questionnaires
from q in dc.Questions.Where(t => t.QuestionnaireId == qs.QuestionnaireID)
from r in dc.Responses.Where(qr => qr.QuestionID == q.QuestionId).DefaultIfEmpty()
where qs.QuestionnaireID == QuestionnaireId
select new
{
qs.Description,
Questions = q,
Responses = r
}).Single();
foreach(var question in questAires.Questions)
{
}
questAires.Questions will only resolve to a single question, and you will get one questAires object for each question (which will cause .Single() to throw).
I guess you want something like this:
var questAires = (from qs in dc.Questionnaires
select new {
qs.Description,
Questions = from q in dc.Questions where q.QuestionnaireId == qs.QuestionnaireID
select new {
Question = q,
Response = (from r in dc.Responses where r.QuestionID == q.QuestionId select r).DefaultIfEmpty()
}
}).Single()
q actually resolves to a single item from the enumerable dc.Questions.Where(...), so yeah, you're only going to get a single item - not an enumerable - for Questions.