With vuejs, how do I get firebase (vuefire) object into component data - firebase

Using firebase 4.10.1 and vuefire 1.4.5.
I have confirmed that I have initialized firebase, exported a db const, and imported vuefire correctly.
I am trying to load my firebase object (JSON) onto my dataTable component data.
I am trying this:
export default {
firebase: function () {
return {
fbObj: db.ref('collection')
}
},
data () {
return {
dataTable: fbObj
}
}
}
It's wired up correctly because if I use {{ fbObj }} in my template I get the JSON object displayed in full. However, if I try to load it onto the dataTable I get "fbObj is not defined" as console error.
How can I load my firebase object onto the dataTable?

The code:
firebase: function () {
return {
fbObj: db.ref('collection')
}
},
Creates a this.fbObj available to your Vue instance. So instead of dataTable: fbObj the correct would be more like:
data () {
return {
dataTable: this.fbObj // but even this won't work
}
}
But that won't work. You can't do it because that data() initialization code will be executed before the fbObj has been initialized (it takes a bit of time to update it from firebase).
So if you want dataTable to refer to that collection, either:
Rename the firebase object to dataTable:
firebase: function () {
return {
dataTable: db.ref('collection')
}
},
Or create a computed property:
firebase: function () {
return {
fbObj: db.ref('collection')
}
},
computed: {
dataTable() {
return this.fbObj;
}
}
Then you can use this.dataTable in the Vue instance JavaScript or dataTable in the template.

Related

invalid Firebase binding source when trying to use readyCallback with vuefire

This is my first time using Vuefire. I want to render some data after the data is loaded using db.ref('page_data'). In the docs, I have read that you can use a function inside of firebase: {} to have a callback when its ready called readyCallback: function(){}
but for some weird reason when I use this firebase throws an error:
invalid Firebase binding source
My <script> tag looks like this
import { db } from "./firebase"
export default {
name: 'App',
firebase: {
data: db.ref('page_data'),
readyCallback: function(){
console.log("Ready!")
}
},
data(){
return{
data: ui_data,
}
}
}
If i remove readyCallback no errors are shown, but the problem is that if i try to render the data before the request is finished the vue app errors out on me.
readyCallback should be nested inside:
firebase: {
data: {
source: db.ref('page_data'),
readyCallback: function(){
console.log("Ready!")
}
}
},

Redirect page if no results from Firebase query

I am using VueJS and Firebase to return results for users, this works correctly
export default{
firebase() {
return{
cSites: db.ref('users/').orderByChild('url').equalTo(this.$route.params.uid)
}
}
}
I am trying to work out how to redirect the app to another page if no results are returned but cant seem work out how. If tried with the readyCallback() function, but together with the existing firebase function did not work.
Thanks in advance for any help.
I'm extrapolating from the docs and the source code, maybe this will work for you
firebase: function() {
return {
cSites: {
source: db.ref('users/').orderByChild('url').equalTo(this.$route.params.uid),
readyCallback: function () {
if (!this.cSites) {
this.$route.router.go('/'); // test and redirect here
}
}
}
}
}
Note when testing the 'function syntax', I get a warning in the console, but the result is ok.
[Vue warn]: Invalid value for option "firebase": expected an Object, but got Function.
Ref Github vuefire issue #133
It's a false alarm. You can use a function for the firebase property. The warning shouldn't appear.
For reference, vuefire.js
function bind (vm, key, source) {
var asObject = false
var cancelCallback = null
var readyCallback = null
// check { source, asArray, cancelCallback } syntax
if (isObject(source) && source.hasOwnProperty('source')) {
asObject = source.asObject
cancelCallback = source.cancelCallback
readyCallback = source.readyCallback
source = source.source
}
To elaborate, cSites is the source object, with properties source and readyCallback.
Using the function syntax allows a kind of 'late binding', so that 'this' has a value at the time the function is called.

Ionic and SQLite wait until database info is loaded

I have a project on Ionic where I need to render some information of the database in the home page, something like a TODO program.
I already have some information on the database and I'm trying to render the list of items but I have the next problem:
First the home page is loaded without any result
Then the data from the database is loaded and printed on the screen
The problem is I want the view to wait until the database info is loaded until showing anything, I'm wondering if I can use some kind of loading icon.
I've followed the answer here: Open database before main controller is called in Ionic and SQlite
I have the database initialization working but as I've said, the data is loaded after the view is rendered.
I've tried using $ionicLoading but I didn't get any good result
This is my view:
.controller('homeCtrl', function ($scope, $state, $cordovaSQLite, DB) {
$scope.$on('$ionicView.enter', function() {
tasks = []
var query = "SELECT * FROM task;";
$cordovaSQLite.execute(DB.db, query, []).then(function(results) {
if(results.rows.length > 0) {
for (i=0; i<results.rows.length; i++){
console.log("SELECTED -> " + results.rows.item(0).title);
$scope.tasks.push(results.rows.item(i))
}
} else {
console.log("No results found");
}
}, function (err) {
$scope.tasks = [];
console.error(err);
});
$scope.tasks = tasks;
});
})
This is a video example of the issue I'm having right now:
https://youtu.be/H2fUYQuV3xg
Finally I found a solution following the advice of using resolve in my routes.
.state('home', {
url: '/',
templateUrl: 'templates/home.html',
controller: 'homeCtrl',
resolve: {
tasks: function(DB) {
return DB.getTasks();
});
}
}
})
I have a factory called DB where I have some functions to retrieve data from the database. On this example I load the tasks before entering on the URL using DB.getTasks()
To load the variable tasks resolved on the route I have to add the variable name on the function like this:
app.controller('homeCtrl', function (tasks) {
$scope.tasks = tasks;
})

Meteor 1.3 + React: detect subscription failure?

I have a simple Meteor subscription, and I display a loading message while the data is being loaded. But I don't know how to display error message if subscription failed.
export const MyAwesomeComponent = createContainer(() => {
let sub = Meteor.subscribe('some-data');
if (!sub.ready()) return { message: 'Loading...'};
if (sub.failed()) return { message: 'Failed.' }; // How to do this?
return {
data: Data.find().fetch()
}
}, MyInternalRenderComponent);
Problem is, the subscription object doesn't have a failed() method, only a ready() query. How to pass the failure of a subscription as props in a createContainer() method?
I know the Meteor.subscribe method has an onStop callback for this case, but I don't know how to glue it toghether that to pass a property.
After a lot of researching I managed to get this working and I think it answers your question.
Bear in mind I'm using Meteor 1.6, but it should give you the info to get it working on your side.
On the publication/publish:
try {
// get the data and add it to the publication
...
self.ready();
} catch (exception) {
logger.error(exception);
// send the exception to the client through the publication
this.error(new Meteor.Error('500', 'Error getting data from API', exception));
}
On the UI Component:
const errorFromApi = new ReactiveVar();
export default withTracker(({ match }) => {
const companyId = match.params._id;
let subscription;
if (!errorFromApi.get()) {
subscription = Meteor.subscribe('company.view', companyId, {
onStop: function (e) {
errorFromApi.set(e);
}
});
} else {
subscription = {
ready: () => {
return false;
}
};
}
return {
loading: !subscription.ready(),
company: Companies.findOne(companyId),
error: errorFromApi.get()
};
})(CompanyView);
From here all you need to do is get the error prop and render the component as desired.
This is the structure of the error prop (received on the onStop callback from subscribe):
{
error: String,
reason: String,
details: String
}
[Edit]
The reason there is a conditional around Meteor.subscribe() is to avoid an annoying infinite loop you'd get from the natural withTracker() updates, which would cause new subscriptions / new errors from the publication and so on.

Angular service containing http get call not working with ng-repeat

I have an angular controller that calls a service. The service is responsible for returning data from a json file.
controller:
function projectController($scope, ajaxServices) {
$scope.projects = ajaxServices.getProjects();
}
service:
projectManagerApp.factory('ajaxServices', function ($http) {
return {
getProjects : function () {
$http.get('projects.json', { data: {} }).success(function (data) {
if (window.console && console.log) {
console.log("objects returned: " + data.length); // shows # of items
}
return data //nothing ng-repeated, no console errors.
})
// Exact same data from json file hard-coded, works fine
// when not commented out.
// return [{ "id": 1, "name": "Project 1 }, { "id": 2, "name": "Project 2" }]
}
}
});
html: ng-repeat="project in projects"
In the success function I can see the data returned in the console log but if I try to return the data the ng-repeat ul element on my page is empty. In the same service if I simply return the same data logged to the console hard coded (outside of the success function, of course it works just fine.
How can I return the data into the ng-repeat using my ajax call?
I'm just as new to Plunker as I am Angular but here is my attempt at a Plunk:
http://plnkr.co/edit/ALa9q6
$http is asynchronous, therefore the call to getProjects will return nothing. Using $q you can receive an instance to a promise which will receive the data when available.
Using $q
Here an example using $q:
http://plnkr.co/edit/U72oJblvrVEgYt2mTmU2?p=preview
Using $resource
Alternatively, you can use $resource especially if your server code is RESTful, which requires adding the following dependency in your scripts:
//ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular-resource.js
This is a 1st review of your code to use $resource: http://plnkr.co/edit/tLOAaXZHdGgWOok3Sdc8?p=preview
But you can simplify and shrink it more to this:
http://plnkr.co/edit/pKO6k6GxJ1RlO8SNvqUo?p=preview
This is the new app.js file:
angular.module('app', ['ngResource'])
.factory('ProjectsService', ['$resource', function($resource) {
return $resource('projects.json');
}])
.controller('ProjectsController', ['ProjectsService', '$scope', function(ProjectsService, $scope) {
$scope.projects = ProjectsService.query();
}]);
Find more information about $resource here:
http://docs.angularjs.org/api/ngResource.$resource
You need to use $q. Example is here
$http performs asynchronously and may or may not be finished at any given point in time which is why your return statement dont work.
Use $q or simply handle the promise inside the controller:
Service:
projectManagerApp.factory('ajaxServices', function ($http) {
return {
getProjects : function () {
return $http.get('projects.json', { data: {} })
}
}
});
Controller:
function projectController($scope, ajaxServices) {
ajaxServices.getProjects().success(function (data) {
if (window.console && console.log) {
console.log("objects returned: " + data.length);
}
$scope.projects = data
});
}
Plunk
If you want data to be loaded before the page
Is loaded you can use 'resolve' property
For the module.
Have a look in the docs for details.

Resources