How to use a variable for method name - flutter

I want to use a variable to access a certain value in my hive database:
In the code below if I use myBox.getAt(i).attributeSelect I get an error because attributeSelect is not defined for the box.
If I use myBox.getAt(i).test it works. How can I make flutter recognise that attributeSelect is a variable and put the value there? I have a total of 181 different variables the user can choose from. Do I really need that many if clauses? The variables are booleans. So I want to check if that attribute is true for the document at index i.
Error: NoSuchMethodError: 'attributeSelect'
method not found
Receiver: Instance of 'HiveDocMod'
attributeSelect = 'test'; //value depends on user choice
Future<void> queryHiveDocs() async {
final myBox = await Hive.openBox('my');
for (var i = 0; i < myBox.length; i++) {
if (attributeSelect == 'All Documents') {
_hiveDocs.add(myBox.getAt(i)); // get all documents
//print(myBox.getAt(24).vesselId);
} else {
// Query for attribute
if (myBox.getAt(i).attributeSelect) {
_hiveDocs.add(myBox.getAt(i)); // get only docs where the attributeSelect is true
}
}
}
setState(() {
_hiveDocs = _hiveDocs;
_isLoading = false;
});
}

I solved it the annoyingly hard way:
if (attributeSelect == 'crsAirCompressor') {
if (myBox.getAt(i).crsAirCompressor) {
_hiveDocs.add(myBox.getAt(i));
}
} else if (attributeSelect == 'crsBatteries') {
if (myBox.getAt(i).crsBatteries) {
_hiveDocs.add(myBox.getAt(i));
}...

Related

Flutter null or emptylist

it's just a small question about dart/flutter code.
I saw this code today :
Future<List<String>?> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return null;
}
} else {
return null;
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
I don't understand interest of returning null with List? . Isn't better to write this code ?:
Future<List<String>> getAtSignListFromKeychain() async {
var atsignMap = await _getAtSignMap();
if (atsignMap.isEmpty) {
// no atsigns found in biometric storage
// read entries from flutter keychain
// for mobile platforms only
if (Platform.isAndroid || Platform.isIOS) {
atsignMap = await checkForValuesInFlutterKeychain();
if (atsignMap.isEmpty) {
return atsignMap;
}
} else {
return List.empty();
}
}
var atsigns = atsignMap.keys.toList();
_logger.info('Retrieved atsigns $atsigns from Keychain');
return atsigns;
}
Or I'm missing something ? Thank you !
First of all, there are always different solutions for different problems. I believe it is better to return a null value for some cases instead of creating an empty list in the memory and returning that. Either way, you have to check the returning value, handle errors, etc. So instead of checking if the list is empty or not, you can use just the ?? operator.
And in some cases, the list you expect with the items in it may be empty. If you return an empty list by default in such cases, you would not know if the list that you expected is really empty or is there a problem.

Flutter : Conditions must have a static type of 'bool'

I'm trying to learn firebase with flutter and i ran into this problem
here is my code :
FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
if (snapshot.data() != null) {
if (snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
} else {
_attending = Attending.unknown;
}
notifyListeners();
});
what is the solution ?
the exact problem is within this line :
if (snapshot.data()!['attending']) {
how can I rewrite this so i wont ruin the current functionality ?
I appreciate your help inadvance
The reason you are getting error -
Conditions must have a static type of 'bool'
because on line snapshot.data()!['attending'] an = sign is missing.
To make your code work just do
if (snapshot.data() != snapshot.data()!['attending']) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
Understanding The Error
I would also like to point out that Dart a stricter language (more like Java in terms of 'truthy' values).
In JavaScript you can use any ‘truthy’ value in a conditional statement. In Dart you cannot use ‘truthy’ values. For example:
var name = 'Joe';
if (name) {
// do something...
OR
var a = 1
if(a){
//this would work in JavaScript
}
You cannot do such things in Java or Dart. The reason is that Dart requires that a condition is a bool true not just a 'truthy' value. You could correct the code by changing it to:
if (name.isNotEmpty)
OR
if(a==1)
{
//these == signs are really important
}
Just store the snapshot.data() to the local map variable and do the operations by that.
_attendingSubscription = FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
final Map<String, dynamic>? data = snapshot.data();
if (data != null) {
_attending = data['attending'] ? Attending.yes : Attending.no;
} else {
_attending = Attending.unknown;
}
notifyListeners();
});

error: Only static members can be accessed in initializers

i will import images BASE64 stored in DB.
code :
profileimage()async{
var userimage1 = await DBHelper().getuserIMAGE1('roro');
print(userimage1);
if(userimage1 == Null){
print('Empty');
}else{
setState(() {
userimage1.map((e) {
tmpimage = e['image0'];
}).toList();
print(tmpimage);
_TmpBytesImage = Base64Decoder().convert(tmpimage);
print(_TmpBytesImage);
return Image.memory(_TmpBytesImage);
});
}
}
File pimage = profileimage(); << error
and i got error 'flutter: Only static members can be accessed in initializers'
how can i do?
You need to call like below.
Future.delayed(Duration.zero, () {
// your code
});
The following items appear wrong:
Your return statement is inside a setstate() function so returns a value from that function.
processImage probably should be
Static Future processImage()
The call should be something like below but not at class level. It also needs to of type Image not of type File.
pimage = await processImage();
If there is nothing in the database, what do you want to return?

How can a range be used across different Word.run contexts?

I have created a taskpane addin for word that runs a search and displays information about the results as a list to the user.
When the user clicks on an item in the list I want to select the range in word to show the user the location of the item.
The addin will then allow the user to perform additional tasks on the range, for example change the font colour.
I am able to run the search and get ranges for display using the function below:
function runSearch(textToFind) {
var items = [];
return Word.run(function(context) {
var options = Word.SearchOptions.newObject(context);
options.matchWildCards = false;
var rangesFind = context.document.body.search(textToFind, options);
context.load(rangesFind, 'text, font, style');
return context.sync().then(function() {
for (var i = 0; i < rangesFind.items.length; i++) {
items.push(rangesFind.items[i]);
context.trackedObjects.add(rangesFind.items[i]);
}
return context.sync();
});
})
.then(function() {
return items;
});
};
However I am having difficulty selecting the range on user click.
I have tried using the ranges context:
function selectRange(range){
range.select();
return range.context.sync();
}
Or using the range in a new Word.run context:
function selectRange(range){
return Word.run(function(context) {
context.load(range);
return context.sync().then(function(){
range.select();
return context.sync();
});
});
}
I have come across a potential method that involves creating a content control for each search result and then reloading all the content controls in the selectRangefunction in the new context and finding the matching control, but that seems very inefficient when I have the range already.
What is the best method for reusing a range across different Word.run contexts?
You cannot use an object across Word.run invocations. Word.run creates a new context every time that it's invoked, whereas the original object is tied to its own context, creating a mismatch.
That being said, you absolutely can, from within a Word.run, add the objects you desire to context.trackedObjects.add(obj), and they will remain as working objects even after Word.run finishes executing. By "working objects" I mean that their path will not get invalidated (think something similar to garbage collection, but for remote objects).
Once you have such object (and it looks above like you do), you should be able to call
range.select();
range.context.sync().catch(...);
If it's not working for you, can you provide an example of the error you're getting?
For completeness sake, I should note that once you add objects to the trackedObjects collection, you're effectively taking memory management of those objects into your own hands. This means that if you don't properly release the memory, you will be slowing down Word by bogging down its memory / range-adjustment chain. So once you're done using the tracked object(s), you should call obj.context.trackedObjects.remove(obj), followed by obj.context.sync(). Don't forget the last part - if you don't do a sync, your request to remove the tracked objects will not be dispatched, and you'll continue to use up the memory.
======= Update 1 =======
Tom, thanks for providing the error message. It looks like this might be a bug in the Word implementation of the APIs -- I'll follow up on that, and someone might reach out to you if there's more questions.
From a conceptual standpoint, you are absolutely on the right path -- and the following does work in Excel, for example:
var range;
Excel.run(function (ctx) {
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
range = sheet.getRange("A5");
range.values = [[5]];
ctx.trackedObjects.add(range);
return ctx.sync();
})
.then(function(){
setTimeout(function() {
range.select();
range.context.trackedObjects.remove(range);
range.context.sync();
}, 2000);
})
.catch(function (error) {
showMessage("Error: " + error);
});
======= Update 2 =======
It turns out there is indeed a bug in the product. However, the good news is that it's easy to fix with a JavaScript-only fix, and in fact we'll do so in the next couple of weeks, updating the CDN.
With the fix, the following code works:
var paragraph;
Word.run(function (ctx) {
var p = ctx.document.body.paragraphs.first;
paragraph = p.next;
ctx.trackedObjects.add(paragraph);
return ctx.sync();
})
.then(function(){
setTimeout(function() {
paragraph.select();
paragraph.context.trackedObjects.remove(paragraph);
paragraph.context.sync()
.then(function() {
console.log("Done");
})
.catch(handleError);
}, 2000);
})
.catch(handleError);
function handleError (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
}
Want even better news? Until the CDN is updated, you can use the code below to "patch" the JavaScript library and make the code above run. You should run this code some time after Office.js has already loaded (i.e., within your Office.initialize function), and before you do a Word.run.
var TrackedObjects = (function () {
function TrackedObjects(context) {
this._autoCleanupList = {};
this.m_context = context;
}
TrackedObjects.prototype.add = function (param) {
var _this = this;
if (Array.isArray(param)) {
param.forEach(function (item) { return _this._addCommon(item, true); });
}
else {
this._addCommon(param, true);
}
};
TrackedObjects.prototype._autoAdd = function (object) {
this._addCommon(object, false);
this._autoCleanupList[object._objectPath.objectPathInfo.Id] = object;
};
TrackedObjects.prototype._addCommon = function (object, isExplicitlyAdded) {
if (object[OfficeExtension.Constants.isTracked]) {
if (isExplicitlyAdded && this.m_context._autoCleanup) {
delete this._autoCleanupList[object._objectPath.objectPathInfo.Id];
}
return;
}
var referenceId = object[OfficeExtension.Constants.referenceId];
if (OfficeExtension.Utility.isNullOrEmptyString(referenceId) && object._KeepReference) {
object._KeepReference();
OfficeExtension.ActionFactory.createInstantiateAction(this.m_context, object);
if (isExplicitlyAdded && this.m_context._autoCleanup) {
delete this._autoCleanupList[object._objectPath.objectPathInfo.Id];
}
object[OfficeExtension.Constants.isTracked] = true;
}
};
TrackedObjects.prototype.remove = function (param) {
var _this = this;
if (Array.isArray(param)) {
param.forEach(function (item) { return _this._removeCommon(item); });
}
else {
this._removeCommon(param);
}
};
TrackedObjects.prototype._removeCommon = function (object) {
var referenceId = object[OfficeExtension.Constants.referenceId];
if (!OfficeExtension.Utility.isNullOrEmptyString(referenceId)) {
var rootObject = this.m_context._rootObject;
if (rootObject._RemoveReference) {
rootObject._RemoveReference(referenceId);
}
delete object[OfficeExtension.Constants.isTracked];
}
};
TrackedObjects.prototype._retrieveAndClearAutoCleanupList = function () {
var list = this._autoCleanupList;
this._autoCleanupList = {};
return list;
};
return TrackedObjects;
}());
OfficeExtension.TrackedObjects = TrackedObjects;
Hope this helps!
~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT
In addition to the TrackedObjects fix the runSearch method needed updating to get the range of the searchResult rather than using the searchResult directly.
function runSearch(textToFind) {
var items = [];
return Word.run(function(context) {
var options = Word.SearchOptions.newObject(context);
options.matchWildCards = false;
var rangesFind = context.document.body.search(textToFind, options);
context.load(rangesFind);
return context.sync().then(function() {
for (var i = 0; i < rangesFind.items.length; i++) {
var range = rangesFind.items[i].getRange();
context.load(range, 'text');
items.push(range);
context.trackedObjects.add(items[items.length-1]);
}
return context.sync();
});
})
.then(function() {
return items;
});
};

How to check if text is found in column in Protractor

I'm trying to assert that a name is displayed in a column of a table. I've written an inResults function that will iterate through a column's text to see if a name exists. Here's what I'm trying:
Page object:
this.names = element.all(by.repeater('row in rows').column('{{row}}'));
this.inResults = function(nameString) {
var foundit = '';
this.names.each(function(name) {
name.getText().then(function(it) {
console.log(it); // each name IS printed...
if(it == nameString) {
console.log('it\'s TRUE!!!!'); // this gets printed...
foundit = true;
}
});
});
return foundit; // returns '' but should be true?
};
Spec expect:
expect(friendPage.inResults('Jo')).toBeTruthy();
Both console statements print as expected... but my expect fails as foundit's value is still ''. I've tried this a number of ways and none are working. What am I missing?
I've devised what I think is a better/cleaner way to solve this. It's less complex and doesn't require locator/css code in the method.
friend.page.js
// locator
this.friendName = function(text) { return element.all(by.cssContainingText('td.ng-binding', text)) };
// method
this.inResults = function(name) {
return this.friendName(name).then(function(found) {
return found.length > 0;
});
};
friend.spec.js
expect(friendPage.inResults('Jo')).toBeTruthy();
I've added this to my protractor_example project on GitHub...
I would recommend you to use filter: http://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.filter
this.inResults = function(nameString) {
return this.names.filter(function(name) {
return name.getText().then(function(text) {
return text === nameString;
});
}).then(function(filteredElements) {
// Only the elements that passed the filter will be here. This is an array.
return filteredElements.length > 0;
});
});
// This will be a promise that resolves to a boolean.
expect(friendPage.inResults('Jo')).toBe(true);
Use map to do this.This will return a deferred that will resolve with the values in an array, so if you have this:
this.mappedVals =element.all(by.repeater('row in rows').column('{{row}}')).map(function (elm) {
return elm.getText();
});
It will resolve like this:
this.inResults = function(nameString) {
var foundit = '';
mappedVals.then(function (textArr) {
// textArr will be an actual JS array of the text from each node in your repeater
for(var i=0; i<textArr.length; i++){
if(it == textArr[i]) {
console.log('it\'s TRUE!!!!'); // this gets printed...
foundit = true;
}
}
return foundit;
});
}
And Use that in Spec file like,
friendPage.inResults('Jo').then(function(findIt){
expect(findIt).toBeTruthy();
});