I'm sending a data ...
....
// upload on file select or drop
$scope.upload = function (file, id) {
id = typeof id !== 'undefined' ? id : null;
Upload.base64DataUrl(file).then(function(base64){
//auth
var fbAuth = FirebaseURL.getAuth();
//Ref
var ref = FirebaseURL.child("users_photos");
ref.push({'image': base64,'removed': true, 'user_id': fbAuth.uid, 'dt_created':Firebase.ServerValue.TIMESTAMP ,'dt_updated':Firebase.ServerValue.TIMESTAMP}, function(error){
if (error) {
alert('Error');
} else {
var newID = ref.key();
//I would like display data insert here?
console.log(DATA RESULT INSERT);
}
});
});
I would like display data inserted.
It is possible to display the last inserted object without query by the key?
Use AngularFire for synchronized collections.
Create a query using limitToLast(1) to always sync the last inserted object.
angular.module('app', ['firebase'])
.constant('FirebaseUrl', '<my-firebase-app>')
.service('rootRef', ['FirebaseUrl', Firebase)
.factory('userItems', UserItems)
.controller('MyCtrl', MyController);
function UserItems($firebaseArray, rootRef) {
return function userItems(uid) {
var itemRef = rootRef.child('items');
var query = itemRef.orderyByChild('uid').equalTo(uid);
return $firebaseArray(query);
}
}
function MyController($scope, userItems, rootRef) {
$scope.items = userItems(rootRef.getAuth().uid);
$scope.addItem = function addItem(item) {
$scope.items.$add(item).then(function(ref) {
var record = $scope.items.$getRecord(ref.key());
// save the data to the other structure
});
};
}
See the section on Complex queries for more info.
Related
I am fairly new to AngularJS and I am practising below exercise with requirement
1.Using the API to get 20 posts and display them on the page along with the user’s
name who created the post and display them on the page.
For this exercise I am using https://jsonplaceholder.typicode.com/ as the data source.
I need to do 2 api calls in same controller
To get list of 20 posts which has userid in it(https://jsonplaceholder.typicode.com/posts)
Based on the above user Id I need to get username (https://jsonplaceholder.typicode.com/users/userId)
Please see my work done in plnkr, I am able to display Post but not username.
Script.js
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$http.get("https://jsonplaceholder.typicode.com/posts").then(function(response) {
$scope.data = response.data;
var postList = [];
for (var i = 0; i < 20; i++) {
var display = {
UserName: $http.get("https://jsonplaceholder.typicode.com/users/" + $scope.data[i].userId).then(function(response) {
$scope.user = response.data;
}),
Post: $scope.data[i].title
}
postList.push(display);
}
$scope.list = postList;
});
});
Index.html
<div ng-repeat="x in list">
Post:{{ x.Post }}
UserName:{{x.UserName}}
</div>
I believe this area is wrong:
.then(function(response) {
$scope.data = response.data;
var postList = [];
for (var i = 0; i < 20; i++) {
var display = {
UserName: $http.get("https://jsonplaceholder.typicode.com/users/"+$scope.data[i].userId).then(function(response){
$scope.user = response.data;
}),
Post: $scope.data[i].title
}
postList.push(display);
}
$scope.list = postList;
});
where you stored a Promise object in your UserName property and produced unexpected result.
to correct this assign the postList after the request has finished:
.then(function(response) {
$scope.data = response.data;
var postList = [];
for (var i = 0; i < 20; i++) {
$http.get("https://jsonplaceholder.typicode.com/users/"+$scope.data[i].userId).then(function(response){
$scope.user = response.data;
var display = {
UserName: "",
Post: $scope.data[i].title
};
$scope.list.push(display);
});
}
$scope.list = postList;
});
Once you implemented this you will encounter a new problem:
since you called $http.get() in a loop and actually used the variable i inside .then() by the time .then() executes the value of i is already in its final form which is i = 20 | data.length which every .then() calls will receive.
in order to overcome this problem the best way I know is to format the entire data first before displaying it:
$http.get("https://jsonplaceholder.typicode.com/posts")
.then(function(response)
{
var data = response.data;
var postList = [];
// this will check if formatting is done.
var cleared = 0;
// create a function that checks if data mapping is done.
var allClear = function () {
if (postList.length == cleared)
{
// display the formatted data
$scope.list = postList;
}
};
for (var i = 0; i < data.length; i++)
{
// create a object that stores the necessary data;
var obj = {
// the ID will be needed to store name;
ID: data[i].userId,
Post: data[i].title,
UserName: ""
};
var url = "https://jsonplaceholder.typicode.com/users/" + obj.userId;
$http.get(url).then(function(response)
{
// find its entry in the array and add UserName;
postList.forEach(function (item)
{
if (item.ID == response.userId)
{
// just add the correct key, but I will assume it is `userName`
item.UserName = response.userName;
// break the loop
return item;
}
});
// increment cleared
cleared++;
// call allClear
allClear();
});
postList.push(obj);
}
}
);
in this way we are sure that the data is complete before displaying it in the view.
as this solution contains a loop to map the result with its original object, we can actually change postList as an object to make it a bit faster:
// var postList = [];
var postList = {};
// instead of pushing we will use the ID as key
// postList.push(obj);
postList[obj.ID] = obj;
and so in this section:
$http.get(url).then(function(response)
{
// instead of looking for the item in .forEach
postList[response.userId].userName = response.userName;
// increment cleared
cleared++;
// call allClear
allClear();
});
hope that helps.
The easy solution would be to add the username to the user object and then push it to the scope list when the promise is resolved
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$http.get("https://jsonplaceholder.typicode.com/posts").then(function(response) {
$scope.data = response.data;
$scope.list = [];
for (var i = 0; i < 20; i++) {
$http.get("https://jsonplaceholder.typicode.com/users/" + $scope.data[i].userId)
.then(function(response) {
var user = {
UserName: response.data.username,
Post: $scope.data[i].title
}
$scope.list.push(user);
});
}
});
});
I use $scope.watch and set and get to pass one data from one controller to another. This works fine, but when I do this with different html files, data is not transferred in my first click. because browser is refreshed. But when I click go back arrow in chrome and set a value and clicked, I can get the value in my second page. How can I resolve this. Please tell me solution.
var data = {
Quantity: ''
};
return {
getQuantity: function() {
return data.Quantity;
},
setQuantity: function(quantity) {
data.Quantity = quantity;
}
};
.controller('DetailsCtrl', function($scope, $http, Data) {
$scope.quantity = '';
$scope.$watch('quantity', function(newValue50, oldValue50) {
if (newValue50 !== oldValue50)
Data.setQuantity(newValue50);
});
})
.controller('FifthCtrl', function($scope, $http, Data) {
$scope.$watch(function() {
return Data.getQuantity();
}, function(newValue50, oldValue50) {
if (newValue50 !== oldValue50)
$scope.quantity = newValue50;
});
})
If you want to store the value between different sessions in the browser you could add the quantity value to the local storage.
Here's an angularjs service/factory example
app.factory('Data', function () {
var data = {
Quantity: ''
};
return {
getQuantity: function () {
if (localStorage.getItem("data") === null) {
data.Quantity = 0;
} else {
var jsonData = localStorage.getItem('data');
data.Quantity = JSON.parse(jsonData);
}
return data.Quantity;
},
setQuantity: function (quantity) {
data.Quantity = quantity;
localStorage.setItem("data", JSON.stringify(data));
}
};
});
Note 1: You actually don't need the object 'data' in this case as you store the value in the storage but I let it stand as is.
Note 2: The localStorage can't store complext types such as objects and you need to make strings of them before you store them, thats why the JSON.stringify() is used.
I need to use $q to wait until my async function has completed and then do something.
However I have tried injecting $q into my angular module as well as my angular functions and I am getting the message $q is undefined.
Can someone tell me how I can go about being able to use this in my code?
Here is the code for the module and the function I want to use $q in respectively
Module
var droidSync = angular.module('droidSync', ['ionic', 'ngRoute', 'ui.router']);
Controller and FunctionIn this case I want to wait for the results.forEach to finish then I want to hide my loading screen using $ionicLoading.hide()
droidSync.controller('mainController', function ($scope, $ionicLoading) {
$scope.syncContacts = function () {
//Display a loading screen while sync is in execution
$ionicLoading.show({
template: '<p>Syncing Contacts...</p><ion-spinner class="spinner-calm" icon="crescent"/>'
});
var table = AzureService.getTable('contact');
table.read().done(function (results) {
results.forEach(function (result) { //THIS NEEDS TO BE COMPLETE BEFORE HIDING LOAD SCREEN
console.log('result is', result);
// If the contact is flagged as deleted check if its on the device and delete it
if (result.isdeleted == true) {
var options = new ContactFindOptions();
options.filter = result.id;
options.multiple = false;
var fields = ["*"];
navigator.contacts.find(fields, findSuccess, findError, options);
function findSuccess(contact) {
if (contact.length > 0) {
console.log("inside the delete area:", contact);
var contactToDelete = navigator.contacts.create();
//It is safe to use contact[0] as there will only ever be one returned as AzureID is unique
contactToDelete.id = contact[0].id;
contactToDelete.rawId = contact[0].id;
console.log('we want to delete this', contactToDelete);
contactToDelete.remove();
console.log('Contact Deleted');
}
else {
console.log('Contact to delete not present on device. Checking next contact');
}
}
function findError() {
console.log('Contact search failed: Deleted Contact Search');
}
}
else {
//create a contact object to save or update
var emails = [];
var phoneNumbers = [];
var name = new ContactName();
var contactToUpdate = navigator.contacts.create();
contactToUpdate.note = result.id;
name.givenName = result.firstname;
name.familyName = result.lastname;
phoneNumbers[0] = new ContactField('mobile', result.mobilephone, true);
phoneNumbers[1] = new ContactField('home', result.homephone, false);
emails[0] = new ContactField('work', result.email, true);
contactToUpdate.name = name;
contactToUpdate.phoneNumbers = phoneNumbers;
contactToUpdate.emails = emails;
//Search for the contact on the device
var options = new ContactFindOptions();
options.filter = result.id;
options.multiple = false;
var fields = ["*"];
navigator.contacts.find(fields, foundSuccess, foundError, options);
function foundSuccess(contact) {
if (contact.length > 0) {
//The contact has been found on the device. Pass in ids for contact, emails and phone numbers to update.
console.log('object to update is object is', contact);
console.log('contact array length is ', contact.length);
contactToUpdate.id = contact[0].id;
contactToUpdate.rawId = contact[0].rawId;
contactToUpdate.phoneNumbers[0].id = contact[0].phoneNumbers[0].id;
contactToUpdate.phoneNumbers[1].id = contact[0].phoneNumbers[1].id;
contactToUpdate.emails[0].id = contact[0].emails[0].id;
console.log('about to save this', contactToUpdate);
contactToUpdate.save(upSuccess, upError);
function upSuccess() {
console.log('updated a contact!');
}
function upError(ContactError) {
console.log('error updating a contact!');
}
}
else {
//The contact does not exist on the device. Just save it.
console.log('non existent contact: ', contactToUpdate);
contactToUpdate.save(saveSuccess, SaveError);
function saveSuccess() {
console.log('saved a contact!');
}
function SaveError() {
console.log('error saving a contact!');
}
}
}
function foundError() {
console.log('Contact search failed: Undeleted Contact Search');
}
} // end else
})) // end forEach
}) // table.read()
}; // scope.syncContacts()
});
So i'd probably do something like this
This is completely untested code so take that for what you will
$q.all is what your going to want to look into
droidSync.controller('mainController', ["$scope", "$q", "$ionicLoading",
function ($scope, $q, $ionicLoading) {
var loop = function(result){
var deferred = $q.defer();
deferred.resolve(// your loop stuff);
return deferred.promise;
};
var loopingFunction = function(results){
var promises = [];
results.forEach(function(result){
promises.push(loop(result));
});
return $q.all(promises);
};
$scope.syncContacts = function () {
//Display a loading screen while sync is in execution
$ionicLoading.show({
template: '<p>Syncing Contacts...</p><ion-spinner class="spinner-calm" icon="crescent"/>'
});
var table = AzureService.getTable('contact');
table.read().done(function (results) {
loopingFunction(results).then(function(){
// do something after it finishes
$ionicLoading.hide()
});
});
};
}]);
I have problem with the Scope of JS functions and/or Angularjs promise and $q. I looked up some examples but I did not get it at all.
In my app I have some data saved in indexeddb of my browser. In Frontend there is an input field with autocomplete function. The value of the input field goes to my angularjs Controller and calls a function. The function should return the found values. The logic of finding values from indexeddb is working fine.
The problem is that I return my array before the values are pushed into the array. So I am not sure if I need to change some stuff in JavaScript scope or to use Angularjs stuff.
Here is my Controller:
var AutocompleteController = function($scope, $http, $q) {
$scope.getCodeFromDB = function(val) {
var codes = [];
var openDbRequest = indexedDB.open('testDb', 1);
openDbRequest.onsuccess = function (e) {
var db = e.target.result;
var transaction = db.transaction("codeobjekt");
transaction.objectStore("codeobjekt")
.openCursor(IDBKeyRange.bound(val, val + '\uffff'))
.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
codes.push(cursor.value.code); //gets filled
console.log(cursor.value.code);
cursor.continue();
}
};
};
console.log(codes); //is empty
return codes;
};
};
Thanks in advance.
in your code you try to use an array filled after the return.
Try using the $q service provides by angular like that.
var AutocompleteController = function($scope, $http, $q) {
$scope.getCodeFromDB = function(val) {
var def= $q.defer(),
codes = [],
openDbRequest = indexedDB.open('testDb', 1);
openDbRequest.onsuccess = function (e) {
var db = e.target.result;
var transaction = db.transaction("codeobjekt");
transaction.objectStore("codeobjekt")
.openCursor(IDBKeyRange.bound(val, val + '\uffff'))
.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
codes.push(cursor.value.code); //gets filled
console.log(cursor.value.code);
cursor.continue();
}
else {
//cursor end
def.resolve(codes);
}
};
};
return def.promise;
};
};
And the usage
//usage
$scope.getCodeFromDB("value")
.then(function(codes) {
//codes filled
});
I'm building an offline HTML page using Angular and using ydn-db for offline storage.
I have a database service like so,
demoApp.SericeFactory.database = function database() {
var database = {
dataStore: null,
admins: [],
students: [],
errors: [],
getadmindata: function(username) {
self = null, that = this
database.dataStore.get('admins', username).done(function(record) {
that.self = record;
return record;
}).fail(function(e) {
console.log(e);
database.errors.push(e);
});
return self; //This does not change.
}
};
database.dataStore = new ydn.db.Storage('DemoApp');
angular.forEach(INITSTUDENTS, function(student) {
database.dataStore.put('students', student, student.matricno);
database.students.push(student);
});
angular.forEach(INITADMINS, function(admin) {
database.dataStore.put('admins', admin, admin.username);
database.admins.push(admin);
});
return database;
I also have a controller that attempts to use the database;
function AppCntl ($scope, database) {
var user = database.getadmindata('user'); //I get nothing here.
}
What I have tried,
I have tried making changing self to var self
I have tried splitting the function like so
rq = database.dataStore.get('admins', 'user');
rq.done(function(record), {
self = record;
alert(self.name) //Works.
});
alert(self) //Doesn't work.
I have gone through questions like this o StackOverflow but nothings seems to be working for me or maybe I have just been looking in the wrong place.
Database request are asynchronous and hence it executes later after end of execution of the codes.
So when the last alert execute, self is still undefined. Secound alert execute after db request completion and it is usual right design pattern.
EDIT:
I have success with following code:
// Database service
angular.module('myApp.services', [])
.factory('database', function() {
return new ydn.db.Storage('feature-matrix', schema);
}
});
// controller using database service
angular.module('myApp.controllers', [])
.controller('HomeCtrl', ['$scope', 'utils', 'database', function($scope, utils, db) {
var index_name = 'platform, browser';
var key_range = null;
var limit = 200;
var offset = 0;
var reverse = false;
var unique = true;
db.keys('ydn-db-meta', index_name, key_range, limit, offset, reverse, unique)
.then(function(keys) {
var req = db.values('ydn-db', keys);
req.then(function(json) {
$scope.results = utils.processResult(json);
$scope.$apply();
}, function(e) {
throw e;
}, this);
});
}])
Complete app is available at https://github.com/yathit/feature-matrix
Running demo app is here: http://dev.yathit.com/demo/feature-matrix/index.html