Firebase Dynamic Querying using results of barcode scanner (Ionic 3 & Angularfire2) - firebase

I have a case where I need to dynamically retrieve the results of a specific book. I would like to retrieve that specific book by using its ISBN number (highlighted in bold below). This is how my database looks like:
{
"results" :
{
"key1" : {
"Character_Depth" : 4,
"Dialogue" : 4,
"Plot" : 5,
"Theme" : 3,
"Writing_Style" : 3,
"bookName" : "Ionic",
"isbnNumber" : "0123456789012"
},
"key2" : {
"Character_Depth" : 4,
"Dialogue" : 4,
"Plot" : 4,
"Theme" : 2,
"Writing_Style" : 4,
"bookName" : "Justin",
"isbnNumber" : "036000291452"
}
}
}
Before I dive into the code, here is some important information I think you need to know. What I am trying to specifically do is use a barcode scanner to scan the ISBN number of a book. Then I would like to use that scanned ISBN number to dynamically retrieve results from that database. With that being said, I need to design my code in such a way that the barcode scanner variable is updated every single time (with each scan) to the new barcode number (already completed). Then that barcode number is fed into the query (which I still can't get to work, and is what I need help with) which retrieves a child node based on that number.
My code:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, AlertController } from 'ionic-angular';
import { BarcodeScanner, BarcodeScannerOptions } from '#ionic-native/barcode-scanner';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { HomePage } from '../home/home';
import { Observable } from 'rxjs/Observable';
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
bookResults: Observable<any[]>;
options: BarcodeScannerOptions;
results: {};
constructor(public navCtrl: NavController,
public navParams: NavParams,
private fire: AngularFireAuth,
private database: AngularFireDatabase,
private barcodeScanner: BarcodeScanner,
private alertCtrl: AlertController) {
/* ########## part of the code where I specifically need help ########## */
this.bookResults = this.database.list('results').valueChanges();
}
/* ########### Barcode scanner function */
async Scan(){
this.results = await this.barcodeScanner.scan();
console.log(this.results);
}
}
Right now, what happens is that the "this.bookResults = this.database.list('results').valueChanges();" retrieves the above database. However, I need some guidance as to how to change my query such that I can retrieve specific child nodes based on the "isbnNumber" instance of each child.
I've tried several things. More recently I've tried:
this.bookResults = this.database.list('/results', {
query: {
orderByChild: isbnNumber,
equalTo: this.results,
}
});
but that didn't work. I've tried other things such as:
this.bookResults =
this.database.list('/results/${this.results}').valueChanges();
but it hasn't worked either.
I've read various stackoverflow threads, so I wouldn't be surprised if this was marked as duplicate. I have tried following the instructions of various threads, yet I felt that the way retrieving information from the database didn't specifically apply to my current situation, as the values used to retrieve specific child nodes where hardcoded into the query. I need a dynamically changing query that adjusts itself based on the barcode scanner's results).
Please let me know if there is anything that was unclear from this post, and I'd be more than happy to help. Also, if you are interested in seeing the source code, here is a link to my github repo containing it:
https://github.com/islamaymansais/honey_scanner
(go to src -> pages -> login -> login.ts)
Thanks for taking the time to read this long post. I am a beginner , I've gone through plenty of posts but unfortunately I was not able to apply the appropriate changes due to my lack of experience with ionic.

As per the readme notes for the Angular firebase library the following should work:
constructor(public navCtrl: NavController,
public navParams: NavParams,
private fire: AngularFireAuth,
private database: AngularFireDatabase,
private barcodeScanner: BarcodeScanner,
private alertCtrl: AlertController) {
this.getData();
}
async function Scan(){
this.results = await this.barcodeScanner.scan();
console.log(this.results);
this.getData();
}
this.getData = () => {
var scanned_Barcode_Text = "";
if (Object.keys(this.results).length > 0){
if(typeof this.results['text'] != 'undefined' && this.results['text'] != ""){
scanned_Barcode_Text = this.results['text'];
}
}
this.bookResults = this.database.list('/results',
ref => (scanned_Barcode_Text != "") ? ref.orderByChild('isbnNumber').equalTo(scanned_Barcode_Text) : ref
).snapshotChanges();
}
call the getData() function in the constructor and also in the success function of the barcode scan.
The orderBy and equal to queries can only be called on the reference objects which is the second parameter(optional) of the AngularFireDatabase object. The usage is similar to the reduce function of the Array.prototype.
Hope this helps.

Try this.
let booksRef = this.firebase.database().ref("results/");
booksRef.orderByChild("isbnNumber").equalTo(scannedBarCode).on("child_added", function(data) {
console.log(data.val());
this.bookResults = data.val();
});
I am considering that you have got the barcode value already and have it in the variable scannerBarCode.
Sidenote: In my opinion, since you are querying the database on ISBN, you should use that instead of key. It will make it simple. Also try the new Cloud Firestore that has better querying features.

Related

javafx binding from list property to arbitrary object property

I am trying to get a class to have a property bound to another class's list property, where the 1st property is derived from a summarizing calculation over the objects in the list. The code below is a simplified version of my production code. (The production code is doing a summary over DateTime objects -- the essential part of the code below is the binding between a list and an object property (here, it is a String for simplicity).)
I have tried various things. One approach was using addListener on the list in the Summary class below but I was running into weird bugs with the listener callback making updates on the Summary object. After doing a bunch of reading I think that a binding between the summary string and the list is more appropriate but I don't know exactly how to hook up the binding to the property?
package com.example.demo.view
import javafx.beans.Observable
import javafx.beans.binding.StringBinding
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleListProperty
import javafx.beans.property.SimpleStringProperty
import javafx.collections.FXCollections
import tornadofx.View
import tornadofx.button
import tornadofx.label
import tornadofx.vbox
class Thing(x: Int) {
val xProperty = SimpleIntegerProperty(x)
val yProperty = SimpleStringProperty("xyz")
}
class Collection {
private var things = FXCollections.observableList(mutableListOf<Thing>()) {
arrayOf<Observable>(it.xProperty)
}
val thingsProperty = SimpleListProperty<Thing>(things)
fun addThing(thing: Thing) {
things.add(thing)
}
}
class Summary(var collection: Collection) {
val summaryBinding = object : StringBinding() {
// The real code is more practical but
// this is just a minimal example.
override fun computeValue(): String {
val sum = collection.thingsProperty.value
.map { it.xProperty.value }
.fold(0, { total, next -> total + next })
return "There are $sum things."
}
}
// How to make this property update when collection changes?
val summaryProperty = SimpleStringProperty("There are ? things.")
}
class MainView : View() {
val summary = Summary(Collection())
override val root = vbox {
label(summary.summaryProperty)
button("Add Thing") {
summary.collection.addThing(Thing(5))
}
}
}
Keep in mind that I made this answer based on your minimal example:
class Thing(x: Int) {
val xProperty = SimpleIntegerProperty(x)
var x by xProperty
val yProperty = SimpleStringProperty("xyz")
var y by yProperty
}
class MainView : View() {
val things = FXCollections.observableList(mutableListOf<Thing>()) {
arrayOf<Observable>(it.xProperty)
}
val thingsProperty = SimpleListProperty<Thing>(things)
val totalBinding = integerBinding(listProperty) {
value.map { it.x }.fold(0, { total, next -> total + next })
}
val phraseBinding = stringBinding(totalBinding) { "There are $value things." }
override val root = vbox {
label(phraseBinding)
button("Add Thing") {
action {
list.add(Thing(5))
}
}
}
}
I removed your other classes because I didn't see a reason for them based on the example. If the collection class has more functionality than holding a list property in your real project, then add just add it back in. If not, then there's no reason to give a list its own class. The summary class is really just two bindings (or one if you have no need to separate the total from the phrase). I don't see the need to give them their own class either unless you plan on using them in multiple views.
I think your biggest problem is that you didn't wrap your button's action in action {}. So your code just added a Thing(5) on init and had no action set.
P.S. The var x by xProperty stuff will only work if you import tornadofx.* for that file.

Firebase/Angularfire: accessing static values of observables

Assume I have a Firebase object with names for some IDs:
people: {
key1: {name: "Bob"},
key2: {name: "Sally"},
...
}
I create an AngularListObservable:
this.people$ = this.angularFireDatabase.list('people');
and feed this into the template as
<span *ngFor="let person of people$ | async">Hello {{person.key}}</span>
Now assume I want to create a new element in people, but base its name on the current number of keys. This requires me to somehow access a static version of people to count its elements. I have found the following three approaches:
One: maintain a current static value via a subscription in ngOnInit:
private currentPeople;
ngOnInit() {
this.people$.subscribe(people => this.currentPeople = people);
}
Then
public create() {
this.people.push({name: "person " + (this.currentPeople.length + 1)});
}
However, this requires me to keep track of the subscription and unsubscribe in ngOnDestroy.
Two: use take on the observable:
public create() {
this.people$.take(1).subscribe(people =>
this.people.push({name: "person " + (people.length + 1)});
);
}
But will this work reliably in getting the current value of the observable?
Three: back off into Angular database itself, entering the world of References and Snapshots, and do
public create() {
this.people$.$ref.once("value").then(peopleSnapshot =>
this.people.push({name: "person " + (peopleSnapshot.numChildren() + 1)});
}
Are any of three approaches considered best practices, or what other pluses and minuses do they have?
For static vars you can use an src/environments/environment.ts folder to hold static information in json format and access them using environment.myvar
In your app.modules.ts you would put
imports: [ AngularFireModule.initializeApp(environment.firebase),
import { environment } from '../environments/environment';

TypeScript - passing a class as an argument, and reflection

I am writing a generic unmarshaller. It converts graph DB data to generated TypeScript (1.8.7) model classes. The input is JSON. The output should be an instance of a model class.
My ultimate goal is to create something like Hibernate OGM, only for Tinkerpop Frames and TypeScript, with REST endpoint in the middle.
What's the right way to pass a class as a parameter and reach it's static members? I want to have something like this:
SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/}, SomeModel);
I've tried to write a method.
Not sure if I am heading in the right direction, feel free to suggest different approaches.
public fromJSON(input: Object, clazz: typeof FrameModel): FrameModel
{
// This only demonstrates access to Framemodel's metadata
// about original Java model classes.
clazz.graphPropertyMapping;
clazz.graphRelationMapping;
let result = {};
...
return result;
}
...
But when I tried to execute this on Plunker, I got execution errors with unuseful stacktrace.
The model superclass looks like this:
/**
* Things common to all Frames models on the Typescript side.
*/
export class FrameModel
{
// Model metadata
static discriminator: string;
static graphPropertyMapping: { [key:string]:string; };
static graphRelationMapping: { [key:string]:string; };
// Each instance needs a vertex ID
private vertexId: number;
public getVertexId(): number {
return this.vertexId;
}
}
Sample model class:
import {TestPlanetModel} from './TestPlanetModel';
import {TestShipModel} from './TestShipModel';
export class TestGeneratorModel extends FrameModel
{
static discriminator: string = 'TestGenerator';
static graphPropertyMapping: { [key:string]:string; } = {
bar: 'boo',
name: 'name',
rank: 'rank',
};
static graphRelationMapping: { [key:string]:string; } = {
colonizes: 'colonizedPlanet',
commands: 'ship',
};
boo: string;
name: string;
rank: string;
public colonizedPlanet: TestPlanetModel[]; // edge label 'colonizedPlanet'
public ship: TestShipModel; // edge label 'ship'
}
I haven't found much material on reflection and class handling in TypeScript.
I know how I would do this in Java.
I know how I would do this in JavaScript.
I understand that I might achieve similar results with decorators, but having fields or static fields seemed a bit simpler, for generated models.
You've maybe already noticed that class members cannot have const keyword. But you could go with static instead. Also member should be public if you want it to be accessible from outside world.
public static graphPropertyMapping: { [key:string]:string; } = {
bar: 'boo',
name: 'name',
rank: 'rank',
};
As for creating result instance:
let result = new clazz();
//copy properties
return result;
If I understand you correctly then here's something to help you get started:
interface Model {}
interface ModelData {}
interface MyModelConstructor<M extends Model, D extends ModelData> {
new(data: D): M;
// static members
graphPropertyMapping: any;
graphRelationMapping: any;
}
class Unmarshaller {
public fromJSON<T>(input: string | ModelData, ctor: MyModelConstructor<T, ModelData>): T {
let data: ModelData = (typeof input === "string") ? JSON.parse(input) : input;
let propertyMapping = ctor.graphPropertyMapping;
let relationMapping = ctor.graphRelationMapping;
// do whatever with the mappings
return new ctor(input);
}
}
(code in playground)
I don't know how your models look like, so I hope this is close enough.
I recently released an enhanced version of the TypeScript compiler that allows exactly what you are expecting: read all (static or not) fields metadata from a class. For example you can write:
interface MyInterface {
active:boolean;
description: string;
}
class MyClass {
id: number;
name: string;
myComplexField: MyInterface;
}
function printMembers(clazz: Class) {
let fields = clazz.members.filter(m => m.type.kind !== 'function'); //exclude methods.
for(let field of fields) {
let typeName = field.type.kind;
if(typeName === 'class' || typeName === 'interface') {
typeName = (<Class | Interface>field.type).name;
}
console.log(`Field ${field.name} of ${clazz.name} has type: ${typeName}`);
}
}
printMembers(MyClass.getClass());
this is the output:
$ node main.js
Field id of MyClass has type: number
Field name of MyClass has type: string
Field myComplexField of MyClass has type: MyInterface
Of course, if you change the members property access of clazz to statics you will retrieve all static members. These information can be accessed at coding time too, so you can use autocompletion.
You can do the same with Interfaces metadata. Simply write MyInterface for example, and access its members.
You can find the project here.

Dart Language: observable

I have two table rows at an HTML file. When the first row gets clicked, it changes its styling via classes.add("active_style"). If the second row gets clicked, I would like to clear the first row styling.
I know that I can just write...
querySelector("#first_row_div").classes.clear();
... in order to clear the first row class (and then resetting its style), but in a bigger code I think that observable would be the best fit.
I don't know if observable works for this. But, if it does, how can I do that?
EDIT/UPDATE: I think that the right question is "is there any way to run a function when a variable gets changed?".
Thanks for the help!
You can make a getter/setter for a field and run your function in the setter.
class MyClass {
String _cssClass;
String get cssClass => _cssClass;
set cssClass(String newClass) {
_cssClass = newClass;
updateDom();
}
void updateDom() {
// do important work here
}
}
You can use a model class that extends Observable.
Here you have to call dirtyCheck() to make Observable check for changes and notify listeners.
Dart also offers the ChangeNotifier mixin. Here you don't need to call any method for dirty-checking. When changes are made listeners are invoked.
A simple example I wrote a while ago while examining the functionality
import 'package:observe/observe.dart';
class Notifiable extends Object with ChangeNotifier {
String _input = '';
#reflectable
get input => _input;
#reflectable
set input(val) {
_input = notifyPropertyChange(#input, _input, val + " new");
}
Notifiable() {
this.changes.listen((List<ChangeRecord> record) => record.forEach(print));
}
}
class MyObservable extends Observable {
#observable
String counter = '';
MyObservable() {
this.changes.listen((List<ChangeRecord> record) => record.forEach(print));
}
}
void main() {
var x = new MyObservable();
x.counter = "hallo";
Observable.dirtyCheck();
Notifiable notifiable = new Notifiable();
notifiable.input = 'xxx';
notifiable.input = 'yyy';
}

Testing criteria in Grails 2.2

One of the reasons we are moving from Grails 1.3.7 to 2.2 is for the ability to unit test our (many) criteria.
And the first thing we have run into with criteria testing is this:
Property [nightly.id] is not a valid property of class [com.litle.bldvwr.Result]
at grails.gorm.CriteriaBuilder.validatePropertyName(CriteriaBuilder.java:968)
What we have is a simple many to one relationship between result and nightly.
Each Result has 1 nightly. There is no direct relationship between Nightly and Result.
Updated
The specific code is:
Nightly.groovy:
package examples
import java.util.Date;
class Nightly {
String name
String status
static constraints = {
status nullable:true
name unique: true, nullable: false, blank: false
}
static mapping = {
}
String toString () {
name +' ' + status
}
}
Result.groovy:
package examples
import java.util.Date;
class Result {
String status
String name
String type
Nightly nightly
static mapping = {
}
Result() {
}
static def gimmeCountByNightlyAndStatusAndRerunIsNull(def nightly, def status) {
def count = Result.createCriteria().count {
and {
eq('nightly.id', nightly.id)
eq('status', status)
isNull('rerun')
}
}
return count
}
}
ResultTests.groovy
package examples
import grails.test.mixin.*
import org.junit.*
#TestFor(Result)
#Mock(Nightly)
class ResultTests {
void testCriteriaMess () {
//this test will fail due to: Property [nightly.id] is not a valid property of class [examples.Result]
Nightly night = new Nightly( name:'nightly1', status:'Success')
night.save(validate:false)
Result res = new Result(status: 'SUCCESS', type: 'INTEGRATION')
res.nightly = night
res.save(validate:false, flush:true)
def count = Result.gimmeCountByNightlyAndStatusAndRerunIsNull(night, 'SUCCESS')
assertTrue count==0
}
}
The above code is from a brand new Grails 2.2 project as created with GGTS 3.1
Except for the code above, everything else in the project is complete boiler plate has generated.
I would expect that, as it does against the actual database, 'nightly.id' would be translated into the nightly_id column of the Result table.
Is this an issue with how GORM is being mocked in 2.2, or are we missing something?
You should change the query to
def count = Result.createCriteria().count {
and {
eq('nightly', nightly)
eq('status', status)
isNull('rerun')
}
}

Resources