My objective is to pass data from page to page. However this error is bugging me. i have declare the navCtrl at the constructor
My constructor for request.ts
constructor(public navCtrl: NavController, public navParams: NavParams, angFire: AngularFireDatabase) {
this.request = angFire.list('/request');
this.userreq = angFire.list(`${this.userkey}`);
this.reqdetails = angFire.list('reqdetails');
}
my html page for request.html
<button class="nearby" ion-button large (click)="openMapPage()">Nearby</button>
my OpenPage method for request.ts
openMapPage()
{
var ref = firebase.database().ref("request");
ref.once("value")
.then(function(snapshot) {
var a = snapshot.exists(); // true
var c = snapshot.hasChild("reqdetails"); // true
var d = snapshot.child('reqdetails').exists();
var requestsKey = snapshot.key;
var requestsValue = snapshot.val();
snapshot.forEach(function(childSnapshot) {
var requestKey = childSnapshot.key;
var requestValue = childSnapshot.val();
var reqdetails = requestValue.reqdetails;
if(reqdetails)
{
this.data = requestKey;
console.log(this.data);
//this.arr.push(requestKey);
//console.log(this.arr);
}
});
this.navCtrl.push(MapPage, {'param1':this.data});
});
}
So after the user clicks on the OpenMapPage() from the request.html it will go to the openMapPage method found in reqeuest.ts and it will render the data to the map.html page
my map.html page:
<ion-list>
<ion-card *ngFor="let user of request | async" class="job">
<ion-avatar class="avatar" item-start>
<img src="../assets/icon/user_male-512.png">
</ion-avatar>
<h2 class="name">{{user.regdetails.username}}</h2>
<p text-wrap class="address"><ion-icon name="compass"></ion-icon> {{user.regdetails.address}}</p>
<p id="key">{{user.$key}}</p>
</button>
</ion-card>
</ion-list>
Now the error i am getting is this:
You should use Arrow functions. By using arrow functions, the this property is not overwritten and still references the component instance (otherwise, the this keyword points to the inner function, and your component's methods and variables are not defined in it):
openMapPage() {
var ref = firebase.database().ref("request");
ref.once("value").then((snapshot) => { // <------ Here!
var a = snapshot.exists(); // true
var c = snapshot.hasChild("reqdetails"); // true
var d = snapshot.child('reqdetails').exists();
var requestsKey = snapshot.key;
var requestsValue = snapshot.val();
snapshot.forEach((childSnapshot) => { // <------ And here!
var requestKey = childSnapshot.key;
var requestValue = childSnapshot.val();
var reqdetails = requestValue.reqdetails;
if (reqdetails) {
this.data = requestKey;
console.log(this.data);
//this.arr.push(requestKey);
//console.log(this.arr);
}
});
this.navCtrl.push(MapPage, { 'param1': this.data });
});
}
You are using a regular function as a callback in snapshot.forEach.
Use arrow function so that this will refer to the class object or use a temporary variable to save this before the call.
snapshot.forEach((childSnapshot) => {
var requestKey = childSnapshot.key;
var requestValue = childSnapshot.val();
var reqdetails = requestValue.reqdetails;
if(reqdetails)
{
this.data = requestKey;
console.log(this.data);
//this.arr.push(requestKey);
//console.log(this.arr);
}
});
Note: Also use arrow function in the outer callback
Related
I'm building an app with Vue.js and Firebase as a backend. I'm retrieving data based on a URL parameter, for instance: http://localhost:8082/?link=fe3b096a8ab1f4d7146ba0ce7555336a85f0532272e748358ec81beb2b17e494
Then my code retrieves the values owneruid and tripuid thanks to this URL parameter. It allows me to get info from the user, such as userphotourl, username, tripphotourl, tripname, tripbegindate, tripenddate. So far it displays the values, so all good.
The variables owneruid and tripuid are stored, but because of the asynchronous, I included calls to functions that use this variables in my first .then(photosSnap => {, to run the rest of the code in a logical order.
Now I want to get all the photourl of all the photos of one trip (tripuid) of a user (owneruid). The database structure is like this :
How can I retrieve all the photourl and display them using v-for ?
My code :
import HelloWorld from './components/HelloWorld'
import Firebase from 'firebase'
let config = {
apiKey: "AIzaSyA9ap6pzsvkOv4tA2rgM6GKl2snKabzel4",
authDomain: "travelertest-e316f.firebaseapp.com",
databaseURL: "https://travelertest-e316f.firebaseio.com",
projectId: "travelertest-e316f",
storageBucket: "travelertest-e316f.appspot.com",
messagingSenderId: "605093453777"
}
let app = Firebase.initializeApp(config);
let database = app.database();
let photosRef = database.ref('trips');
function GetURLParameter(sParam)
{
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++)
{
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == sParam)
{
return sParameterName[1];
}
}
}
let link = GetURLParameter('link');
console.log(link);
//var owneruid = 'bCbADd1qJqhoVbDg0QCDIlq5eMx1';
//var tripuid = '-Kiqtd3BxPX8WvpOTxsW';
var owneruid = '';
var tripuid = '';
database.ref(`links/${link}`).once('value').then(photosSnap => {
var obj = photosSnap.val();
owneruid = obj['owneruid'];
tripuid = obj['tripuid'];
console.log(owneruid);
console.log(tripuid);
getUserInfo();
getTripInfo();
getTripDate();
});
function getUserInfo() {
database.ref(`user_profiles/${owneruid}`).once('value').then(photosSnap => {
var obj = photosSnap.val();
var userphotourl = obj['photourl'];
var username = obj['name'];
$('.userphoto').attr('src', userphotourl);
$('.username').html(username);
});
}
function getTripInfo() {
database.ref(`trips/${owneruid}/trips/${tripuid}`).once('value').then(photosSnap => {
var obj = photosSnap.val();
var tripphotourl = obj['photourl'];
var tripname = obj['name'];
$('#tripcoverphoto').attr('src', tripphotourl);
$('.tripname').html(tripname);
});
}
function ConvertDate(DateInSeconds) {
var tripbegindateseconds = DateInSeconds;
var tripbegindatefull = new Date(0); // The 0 there is the key, which sets the date to the epoch
tripbegindatefull.setUTCSeconds(tripbegindateseconds);
var tripbeginmonth = tripbegindatefull.getUTCMonth() + 1; //months from 1-12
var tripbeginday = tripbegindatefull.getUTCDate();
var tripbeginyear = tripbegindatefull.getUTCFullYear();
tripbegindate = tripbeginday + "/" + tripbeginmonth + "/" + tripbeginyear;
return tripbegindate;
}
function getTripDate() {
database.ref(`trips/${owneruid}/trips/${tripuid}`).once('value').then(photosSnap => {
var obj = photosSnap.val();
var tripbegindate = ConvertDate(obj['begindate']);
var tripenddate = ConvertDate(obj['enddate']);
$('.tripbegindate').html(tripbegindate);
$('.tripenddate').html(tripenddate);
});
}
/*database.ref(`links/${link}`).once('value').then(photosSnap => {
var obj = photosSnap.val();
var owneruid = obj['owneruid'];
var tripuid = obj['tripuid'];
});
console.log(owneruid);
console.log(tripuid);*/
export default {
name: 'app',
firebase: {
photos: photosRef
}
}
<div id="app">
<div id="profile">
<img class="userphoto" src="" /><br/>
<font size="6" class="username"></font><br/>
<img id="tripcoverphoto" src="" alt="" /><br/>
<font size="8" class="tripname"></font><br/>
<font size="6" class="tripbegindate"></font><font size="6"> - </font><font size="6" class="tripenddate"></font>
</div>
<div id="photoslist" v-for="photo in photos">
<img id="image" height="400" width="400" src={{photo}}/>
</div>
</div>
Hi i am trying to figure out how to loop through a request table with a user key that has only reqdetails. I have tried following the docs, but it's not working.
I just need to filter out all the user key that has only reqdetails only. For example user key of OAJ2WNWQPUfwJCpAJ11FWIA8kPn2 has a reqdetails.
Btw i am following this link:
https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot
Here is my firebase console:
Here is my declaration and constructor
request: FirebaseListObservable<any>;
userkey: FirebaseListObservable<any>;
reqdetails: FirebaseListObservable<any>;
userreq: FirebaseListObservable<any>;
constructor(public navCtrl: NavController, public navParams: NavParams, angFire: AngularFireDatabase) {
this.request = angFire.list('/request');
this.userreq = angFire.list(`${this.userkey}`);
this.reqdetails = angFire.list('reqdetails');
}
Here is my OpenMapPage method
openMapPage()
{
let process = this.request.subscribe(records => {
// your logic
records.forEach(record => {
var ref = firebase.database().ref("request");
ref.once("value")
.then(function(snapshot) {
var a = snapshot.exists(); // true
var c = snapshot.hasChild("reqdetails"); // true
var d = snapshot.child('reqdetails').exists();
if (snapshot.hasChild('reqdetails'))
{
console.log(record.$key);
}
});
});
});
this.navCtrl.push(MapPage);
}
You need to specify the key of your target request or loop on all requests.
If you know the key :
ref.child(REQUEST_KEY).once("value", function(snapshot) {
var requestKey = snapshot.key;
var requestValue = snapshot.val();
var reqdetails = requestValue.reqdetails;
console.log(reqdetails);
}
If you want all requests :
ref.once("value", function(snapshot) {
var requestsKey = snapshot.key;
var requestsValue = snapshot.val();
snapshot.forEach(function(childSnapshot) {
var requestKey = childSnapshot.key;
var requestValue = childSnapshot.val();
var reqdetails = requestValue.reqdetails;
console.log(reqdetails);
});
}
i am trying to show a dynamic data on the ionic slide box with ng-repeat. i am using services to get the data from my sqlite DB but i get nothing. i don't know what to do after 3 days with this issue, here is my code:
template.html
<ion-view>
<ion-nav-title>{{simple.title}}</ion-nav-title>
<ion-content>
<div class="row">
<div class="col col-33 col-offset-33">
<h1 style="font-size: 72px !important;">{{simple.content}}</h1>
</div>
</div>
<div class="row">
<div class="col">
<ion-slide-box show-pager="false" does-continue="true">
<ion-slide ng-repeat="senci in sencillo">
<div class="box">
<h1 style="font-size: 52px !important;">{{senci.sound_title}}</h1>
</div>
</ion-slide>
</ion-slide-box>
</div>
</div>
</ion-content>
</ion-view>
my service.js
angular.module('starter.services', [])
.factory('DBA', function($cordovaSQLite, $q, $ionicPlatform) {
var self = this;
// Handle query's and potential errors
self.query = function (query, parameters) {
parameters = parameters || [];
var q = $q.defer();
$ionicPlatform.ready(function () {
$cordovaSQLite.execute(db, query, parameters)
.then(function (result) {
q.resolve(result);
}, function (error) {
console.warn('I found an error');
console.warn(error);
console.log(error.code + ' / ' + error.message);
q.reject(error);
});
});
return q.promise;
};
// Proces a result set
self.getAll = function(result) {
var output = [];
for (var i = 0; i < result.rows.length; i++) {
output.push(result.rows.item(i));
}
return output;
};
// Proces a single result
self.getById = function(result) {
var output = null;
output = angular.copy(result.rows.item(0));
return output;
};
return self;
})
.factory('Sounds', function(DBA) {
var self = this;
self.getSimple = function(simpleId) {
var parameters = [simpleId];
return DBA.query("SELECT * FROM letters WHERE Id = (?)", parameters)
.then(function(result) {
return DBA.getById(result);
});
};
self.getSimpleArr = function(Id) {
var parameters = [Id];
return DBA.query("SELECT * FROM words WHERE letter_id = (?)", parameters)
.then(function(result) {
return DBA.getById(result);
});
};
return self;
});
controller.js
.controller('SoundsSimpleCtrl', function($scope, Sounds, $stateParams, $ionicSlideBoxDelegate) {
$scope.sencillo = [];
$scope.getSimple = function($stateParams) {
Sounds.getSimple($stateParams.simpleId).then(function(single){
$scope.simple = single;
$scope.getArrSimple($scope);
});
};
$scope.getArrSimple = function($scope){
Sounds.getSimpleArr($scope.simple.Id).then(function(detalle){
$scope.sencillo = detalle;
$ionicSlideBoxDelegate.update();
});
};
$scope.getSimple($stateParams);
});
i hope you guys can help me, regards.
Hi people i resolved my problem, i had a bad SQl Request, im so sorry for be annoying, i just changed to use my service function from getById() to getAll() (these functions are being taken from DBA Factory) like this:
self.getSimpleArr = function(value) {
var parameters = [value];
return DBA.query("SELECT * FROM words WHERE letter_id = (?)",parameters)
.then(function(result){
return DBA.getAll(result);
});
};
the getById() function was returning only the first row of the request, absolutely MY BAD. Regards
I am querying data via breeze.js which works fine the first time. The second time the view isn't updated.
html
<a id="linkQDate">Order by Newest</a>
<a id="linkQScore">Order by Score</a>
<div id="questionWrapper">
<ul data-bind="foreach: results">
<li>
<strong><span data-bind="text: Score"></span></strong>
<span data-bind="text: Titel"></span>
</li>
</ul>
</DIV>
js
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel;
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded);
function querySucceeded(data) {
dmodel = data;
if (!isApplied) {
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
}
}
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
manager.executeQuery(query).then(querySucceeded);
function querySucceeded(data) {
dmodel = data;
if (!isApplied) {
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
}
}
});
});
If you just using plain JS objects it will not work. Because it does not know when underlying data changes. Use mapping plugin for this to work:
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel;
function querySucceeded(data) {
if (!isApplied) {
dmodel = ko.mapping.fromJS(data);
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
} else {
ko.mapping.fromJS(data, dmodel);
}
}
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded);
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
});
});
Working code from Tomas without mappings. It is much faster:
$(document).ready(function () {
var manager = new breeze.EntityManager('/breeze/dbentities');
var isApplied = false;
var dmodel = { results: ko.observableArray() };
function queryFailed(data) {
console.log(data);
}
function querySucceeded(data) {
if (!isApplied) {
for (var i = 0; i < data.results.length; i++) {
dmodel.results.push(data.results[i]);
}
ko.applyBindings(dmodel, $("#questionWrapper")[0]);
isApplied = true;
} else {
dmodel.results.removeAll();
for (var i = 0; i < data.results.length; i++) {
dmodel.results.push(data.results[i]);
}
}
}
$("#linkQDate").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Date");
manager.executeQuery(query).then(querySucceeded).fail(queryFailed);;
});
$("#linkQScore").click(function () {
var query = breeze.EntityQuery.from("Questions").orderBy("Score");
manager.executeQuery(query).then(querySucceeded).fail(queryFailed);;
});
});
I am trying to solve a problem of rendering one template in context of another template with knockout. The outer template doesn't know and shouldn't care about the inner template and its view model. All it cares about is it's own template, a place to embed the inner template passing the name of it and its view model.
So ideally I wish I know how to implement the following binding:
<script type="text/html" id="outerTemplate">
<div class="outer-template" data-bind="here: {}"></div>
</script>
<!-- ko nested: { to: 'outerTemplate', data: { name: 'I am an inner view model' } } -->
<div class="inner-template" data-bind="text: name"></div>
<!-- /ko -->
If anyone knew the knockout well enough to easily outline such kind of binding I would greatly appreciate it.
UPDATE: The feature request was proposed: https://github.com/knockout/knockout/issues/1251
The template binding allows you to dynamically select the template name to use, so you can do something like:
<script id="outer" type="text/html">
<h2>Outer</h2>
<div data-bind="template: { name: tmplName, data: data }"></div>
</script>
<script id="inner" type="text/html">
<h3>Inner</h3>
<input data-bind="value: name" />
</script>
<div data-bind="template: 'outer'"></div>
In this case the view model would look like:
var vm = {
tmplName: 'inner',
data: {
name: ko.observable("Bob")
}
};
ko.applyBindings(vm);
The view model could be structured however you want. The key is just that you are passing the template name and data into the template binding.
Sample: http://jsfiddle.net/rniemeyer/LHhc8/
There is a working example I made myself: http://jsfiddle.net/m34wp/4/
var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
function disposeOldComputedAndStoreNewOne(element, newComputed) {
var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
if(oldComputed && (typeof (oldComputed.dispose) == 'function')) {
oldComputed.dispose();
}
ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
}
function makeArray(arrayLikeObject) {
var result = [];
for(var i = 0, j = arrayLikeObject.length; i < j; i++) {
result.push(arrayLikeObject[i]);
}
;
return result;
}
function moveCleanedNodesToContainerElement(nodes) {
var nodesArray = makeArray(nodes);
var container = document.createElement('div');
for(var i = 0, j = nodesArray.length; i < j; i++) {
container.appendChild(ko.cleanNode(nodesArray[i]));
}
return container;
}
ko.bindingHandlers['nested'] = {
'init': function (element, valueAccessor) {
var elementType = 1;
var commentType = 8;
var bindingValue = ko.utils.unwrapObservable(valueAccessor());
if(element.nodeType == elementType || element.nodeType == commentType) {
// It's an anonymous template - store the element contents, then clear the element
var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element);
var container = moveCleanedNodesToContainerElement(templateNodes);
new ko.templateSources.anonymousTemplate(element)['nodes'](container);
}
return {
'controlsDescendantBindings': true
};
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = ko.utils.unwrapObservable(valueAccessor());
var outerTemplateName = options['to'];
var dataValue = ko.utils.unwrapObservable(options['data']) || viewModel;
var innerContext = bindingContext['createChildContext'](dataValue);
innerContext.innerTemplateElement = element;
var templateComputed = ko.renderTemplate(outerTemplateName, innerContext, options, element);
disposeOldComputedAndStoreNewOne(element, templateComputed);
}
};
ko.bindingHandlers['here'] = {
'init': function (element, valueAccessor) {
return {
'controlsDescendantBindings': true
};
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var templateElement = bindingContext.innerTemplateElement;
if(viewModel != null) {
var innerContext = bindingContext['createChildContext'](viewModel);
var templateComputed = ko.renderTemplate(templateElement, innerContext, {
}, element);
disposeOldComputedAndStoreNewOne(element, templateComputed);
} else {
}
}
};
ko.virtualElements.allowedBindings['nested'] = true;