Vuefire Firebase update issues - firebase

I'm having som issues with updating Firebase from VueFire. I m trying to use the following method, but it yells at me if I leave any field blank (which is supposed to happen often in setup) Any idea why this gets mad if .update with a blank field?
Error: Uncaught Error: Firebase.update failed: First argument contains undefined in property 'businesses.somebusiness.video'
updatePost(post) {
postsRef.child(post['.key']).update({
name: post.name,
video: post.video,
story: post.story,
cover: post.cover,
card: post.card
})
},
At one point I had the above re-written like so:
updatePost: function (post) {
const businesschildKey = post['.key'];
delete post['.key'];
/* Set the updated post value */
this.$firebaseRefs.posts.child(businesschildKey).set(post)
},
It worked amazingly but deleting the key seemed to cause weird ordering issues in Vue. I would prefer to stick with the top method if I can find a way to not have it trow an error if one is left blank.

According to this post,
When you pass an object to Firebase, the values of the properties can
be a value or null (in which case the property will be removed). They
can not be undefined, which is what you're passing in according to the
error.
Your error message suggests that post.video's value is undefined. You can use logical-or to provide a fallback value like so:
video: post.video || null,
That means whenever post.video has a false-y value, the expression will evaluate to null. That could catch empty string or numeric 0, though. To be more precisely correct, you should use
video: typeof post.video === 'undefined' ? null : post.video,
If you need to do this check for many values, you can write a function for it:
function nullIfUndefined(value) {
return typeof value === 'undefined' ? null : value;
}
then your expression would just be
video: nullIfUndefined(post.video),

Related

QML Firebase startAt returns undefined

I am working on a 'typeahead’ type function which will check my Database with the current typed text to provide search suggestions of users using Felgo.
Here is the link for Felgos Firebase documentation
As to not search every entry I am looking to use the startAt and limitTo for a lower data use.
However when applying the startAt my searches only return undefined, I have tried testing this by changing my startAt from a variable to explicit data but this still only returns undefined.
My function is below:
function searchUsers(searchString) {
db.getValue("public/nameList/", {
orderByChild: true,
startAt: searchString, //searchString is a variable with my .currentText to search.
limitToFirst: 10,
}, function(success, key, value) {
if(success) {
searchArr = []
searchArr = value
console.debug("Read user value for key", key, "from DB:", value)
}
})
}
I have also tried by passing my var searchString through JSON.stringify(searchString) and also return undefined!
Removing the startAt: query entirely returns the entire result of nameList as expected, but no matter how I try to implement my startAt it always returns undefined.
A sample of my nameList JSON is:
nameList: {
"EddieLaw245" : 530343772383,
"EddieLawrence91" : 530343772385,
"EdwardL91" : 530343772386,
"EdwardLaw" : 530343772384,
"Edwardlawrence91" : 530343772380,
"JoBrownLondon" : 530343772381,
"KatiePrescottHair" : 543592635596,
"Tracey-Sweeting" : 530343772382
}
So with the above example, When I type E it should remove the last 3 entries, and so on.
The problem is that you're specifying orderByChild: true. If we look at the documentation of that:
orderByChild: If present, the queried object will have its properties ordered by values at sub-paths defined by the value of this property. Ordering by child properties makes the filter properties startAt, endAt and equalTo filter by the child property values
It may not be immediately clear from this, but orderByChild allows you to order the results on a property value under each of those nodes. So your code tries to order the child nodes on the value of a property true, which isn't possible (and should actually generate a compile-time error in the library) as the nodes under nameList don't have any child properties of their own. They merely have a key and a value.
What you're looking for is orderByKeys, which orders the child nodes on their keys. So:
db.getValue("public/nameList/", {
orderByKeys: true,
startAt: searchString,
limitToFirst: 10,
}
You'll typically also want to specify an endAt value, to ensure your type-ahead only shows values that start with the search string. If you only allow ASCII values in the keys, the simplest way to do this is:
startAt: searchString,
endAt: searchString + "~",
The ~ here is no magic operator, but merely the last ASCII characters. If you want to allow a broader character set, you'll need to use the last character in that character set - for example \uF7FF is the last code point for Unicode.
Update from OP
Though I'm certian Franks correct with typical Firebase usage; I suspect due to the Felgo plugin I am using the full solution has a slight adjustment;
db.getValue("public/nameList/", {
"orderByKey": true,
"startAt": searchString,
"endAt": searchString+"~",
"limitToFirst": 10,
}, function(success, key, value) {....}
})
Notes on the above - my filters/queries are surrounded by quotation marks "startAt", also instead of orderByKeys, I have used orderByKey

Redux saga: take every action where error is true

Is there a possibility to specify whether the action has its error field set to true?
const response = function*() {
yield takeEvery("CLIENT_RESPONSE", handleResponse);
}
However, we don't know whether the action with type CLIENT_RESPONSE has its error field set to true or not.
I know I can check this in the handleResponse but that seems to be more work than it should. For instance, the handleResponse might get complex because for both the non-error and error case I need to write a lot of code (i.e. I want to have different handlers for both cases).
So is there a way to specify to only take that action when error is set to true?
According to Saga API reference, the pattern (first argument) of takeEvery can be String, Array or Function.
You can achieve what you want by passing a function:
const response = function*() {
yield takeEvery(action => (action.type === "CLIENT_RESPONSE" && !action.error), handleResponse);
}

Flowtype constantly requiring null checks

I'm wondering how to avoid these numerous null checks or at least understand what the point is because it seems counter-productive.
Flowtype is giving me an error for this if I omit the null check:
var myEl = new MyElement()
if (document.body != null) { // error on next line if omitted
document.body.appendChild(myEl)
}
I have to do that null check for the document body in every single callback too, because who knows, maybe the body is null here right?!
I think this is total overkill. Not only that, but what's the point of such a simple nullcheck? It will just silently skip over a vital part of the program and exhibit undefined behavior somewhere else and make debugging the app that much harder.
I'd really prefer just having a null exception at this point if an error ever happens here, because to be really sure this tiny 2-line code segment that I'd write in javascript would have to be like this in flowtype:
var myEl = new MyElement()
if (document.body != null) {
document.body.appendChild(myEl)
} else {
console.error("null error")
}
So 4 additional code lines and some nesting just to trace something I'd get for free if I just let the app run into an error. And I need those 4 lines on every single querySelector. On every single document.body. On every single getElementByTagName. This alone probably increases my entire codebase by 10%.
What's the point of enforcing this so strictly?
In other languages I'd also be able to try-catch around these hotspots gradually as needed, flow doesn't let me do that either. It shows errors whether I add a try-catch or not.
By using a type checker, you are opting into the rules that it enforces. Accessing a property on a nullable type is one of those restrictions. So if you want to have exceptions for null values, you need to explicitly throw to prove to Flow that it is what you want. You could for instance make a module like
if (!document.body) throw new Error("Unexpectedly missing <body>.");
export const body: HTMLElement = document.body;
export function querySelector(el: HTMLElement, selector: string): HTMLElement {
const result = el.querySelector(selector);
if (!result) throw new Error(`Failed to match: ${selector}`);
return result;
}
By throwing, these functions explicitly say "I will return an element" in all cases, and in null cases, they will throw exceptions.
Then in your normal code, you are guaranteed you can use those
import {body, querySelector} from "./utils";
body.appendChild(document.createElement('div'));
querySelector(body, 'div').setAttribute('thing', 'value');
and it will typecheck property.
When I know for sure that my variable won't be null and Flow doesn't, I use an unwrap() function:
export default function unwrap<T>(value: T): $NonMaybeType<T> {
if (value !== null && value !== undefined) return value
throw new Error('Unwrapping not possible because the variable is null or undefined!')
}

#ngrx/store Ignore first emitted value

store.select() emits previous store state.
Is it possible to subscribe to changes from "this point forward" without getting the previous store value?
If you are not interested in the first emitted value, you should be able to use the skip operator:
store.select(...).skip(1)...
skip operators need piping now, you can use skip like this:
store.pipe(select(...), skip(1));
In terms of the 'hacky' part, it is a standard practice in ngrx to set an initial state with properties set to null. and that value gets emitted initially. so the first value you get will be null in these cases.
Alternatively you could also consider skipwhile(https://www.learnrxjs.io/learn-rxjs/operators/filtering/skipwhile) and use it like this:
store.pipe(select(...), skipWhile(val => val === undefined));
where undefined is the initial value of the property you are interested in. Rather than setting the initial value of the property to undefined, you could use null as the initial value as well, and change the above skipwhile() accordingly.
Just sharing my thoughts (and solution) after reading #Niz's answer.
This is a perfect, practical example of how to utilize the difference between null and undefined. When you initialize your state with null, you're basically saying:
I don't care about differentiating the nullable future state from the
initial one. I don't care if the user is null because he has signed
out or because he just didn't sign in
However, in some cases this could be insufficient. Think about a case when you need an asynchronous call (implemented in effects) in order to know if you have an active user session. Based on the selection result, you should determine whether to show a login modal or redirect to a content page. With initial user state set to null, you'd pop up that modal and then immediately hide it when that asynchronous call returns a session value.
With initial state set to undefined you can make that differentiation, saying:
Initially, I know nothing about my state, then it's undefined. When I know it should be empty, then I'll set it to null.
Therefor, as a practical solution, I set everything on the app's initialState to undefined. In the example above, I need to know if the login modal should be displayed after the asynchronous call resolves. skipWhile(val => val === undefined) will do the job for sure, but repeating it over and over again feels a little tedious. Plus, it's not really descriptive to our use case. I created a rxjs-custom-operators.ts with a shortened implementation:
import { Observable } from "rxjs";
import { skipWhile } from "rxjs/operators";
export const skipInitial = () => {
return <T>(source: Observable <T>): Observable<T> => {
return source.pipe(skipWhile(value => value === undefined));
};
};
Usage:
navigateOnLoad(): void {
this.store.pipe(select(selectAuthUser), skipInitial()).subscribe((authUser: CognitoUser) => {
// Navigate to login if !authUser, else navigate to content...
});
}

Cannot read property of undefined, but property exists

I am getting a curious error in a template helper and I was hoping someone could lay eyes on it with me. Basically the error I'm getting in the console of the client is that the getArena().height is undefined. However, console.log(getArena().height) returns the correct property value. It appears to be a timing issue causing me to get the error, but my application is actually working. What can I do to alleviate this console error?
//My template helper function
yGrids: function() {
console.log(getArena);
console.log(getArena().height);
var yArray = [];
for (var i=0;i<(getArena().height);i++){
yArray.push({});
}
return yArray;
},
// The console results
function getArena() { // 50
return Arenas.findOne(Session.get('arena_id')); …
Exception in template helper: TypeError: Cannot read property 'height' of undefined
at Object.yGrids (http://localhost:3000/app/app.js?hash=c17abf51d6af6541e868fa3fd0b26e34eea2df28:94:35)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2994:16
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1653:16
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3046:66
at Function.Template._withTemplateInstanceFunc (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3687:12)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:3045:27
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?hash=65db8b6a8e3fca189b416de702967b1cb83d57d5:172:18)
at http://localhost:3000/app/app.js?hash=c17abf51d6af6541e868fa3fd0b26e34eea2df28:24:22
at .<anonymous> (http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:2754:17)
at http://localhost:3000/packages/blaze.js?hash=ef41aed769a8945fc99ac4954e8c9ec157a88cea:1875:20
function getArena() { // 50
return Arenas.findOne(Session.get('arena_id')); …
2
This is a very common issue in Meteor helpers when referring to a collection which may not yet have been loaded via a subscription. In general you want to show a loading template instead of your actual layout until your subscription is ready. Or (less elegant) you can defend yourself with:
var arena = getArena();
var height = arena && arena.height;
Whatever getArena() returns you ought to store it in the reactive variable by setting the reactive variable and you can access the reactive var in helper by get() method

Resources