Firebase loading $scope view enter doesn't load - angularjs

I have a loading problem in Firebase. I want to display a list of images when I open the view but nothing happens till i go back ( there is a flash and i can see my photo list). It's working but not displaying in the opening.
What am i missing please ?
There is the beginning of my Controller view:
'Use Strict';
angular.module('App').controller('valider_photosController', function($scope, $state, $localStorage, Popup, Firebase, $firebaseObject, $ionicHistory, $ionicPopup, $ionicModal, $cordovaCamera) {
$scope.imagestab = [];
var ref_logements = firebase.database().ref('logements');
var ref_images = firebase.database().ref('images');
ref_logements.child(id_logement).child('images').on('child_added', added);
function added(idxSnap, prevId){
ref_images.child(idxSnap.key).once('value', function(datasnap){
var bidule = datasnap.val();
bidule['key'] = datasnap.key;
$scope.imagestab.push(bidule);
console.log('La valeur'+datasnap.key+'donne '+datasnap.val());
});
};
});

Since firebase works with asynchronous calls, by the time firebase responds with your data the angular cycle had already finished and you won't have your scope updated. You can force it by using $scope.$apply();.
ref_images.child(idxSnap.key).once('value', function(datasnap){
var bidule = datasnap.val();
bidule['key'] = datasnap.key;
$scope.imagestab.push(bidule);
$scope.$apply();
});
There is a tool that integrates angular and firebase in a way that you won't have to be concerned with things such as applying the scope. Its called angularfire. I totally recommend you to start using it in your application.
With angularfire you can get your data simply using
$scope.bidule = $firebaseObject(ref_images.child(idxSnap.key));
or
$scope.images = $firebaseArray(firebase.database().ref('images'));

I created a Factory
.factory('Firebase', function ($firebaseArray, $firebaseObject) {
var ref = firebase.database().ref();
return {
all: function (section) {
var data = $firebaseArray(ref.child(section));
return data;
},
getById: function (section, id) {
var data = $firebaseObject(ref.child(section).child(id));
return data;
},
get: function (section, field, value) {
var data = $firebaseArray(ref.child(section).orderByChild(field).equalTo(value));
return data;
}
};
})
And then in my controller, i replaced like you said :
var ref_logements = firebase.database().ref('logements');
var ref_images = firebase.database().ref('images');
ref_logements.child(index2).child('images').on('child_added', added);
function added(idxSnap, prevId) {
var monimage = Firebase.getById('images', idxSnap.key);
$scope.imagestab.push(monimage);
};
And it Works like a charm ! Thank you again :)

Related

404 error sporadically occurs on umbraco area module with angular

I have an Umbraco project with an Area section configured with Angular.
I use the Plugins to integrate the Area with the use of package.manifest like this:
Into edit.controller.js, I have this script:
'use strict';
angular.module("umbraco")
.controller('Administration.AdministrationTree.EditController', function administrationEditController($scope, $routeParams, $http) {
//set a property on the scope equal to the current route id
$scope.id = $routeParams.id;
$scope.url = "";
$scope.canShow = false;
$scope.showIframe = function () {
if ($scope.url === "") {
return false;
}
return true;
};
$scope.canShow = false;
if (!$scope.id) {
return;
}
$http.get('/umbraco/backoffice/administration/CustomSection/GetUrl/?node=' + $scope.id)
.success(function (data) {
$scope.url = JSON.parse(data);
$scope.canShow = $scope.url;
});
});
When I run the project and click on any node in this area, I receive most of the time a 404 error like if the page was not exist. I say "most of the time" because 1 out of 10, it works and the page is displayed.
However, if I put a breakpoint in the javascript function below and I click on any node and resume the javascript after the breakpoint was hitting, the node related html page is displayed correctly.
Anybody know why when I put a breakpoint, Umbraco or Angular are able to resolve 100% of the time the page but not when I don't have any breakpoint in this function?
Thanks
I really hate to answer my own questions but after 2 weeks without answers and a lot of reflections on my side, I finally found a solution to this problem.
What was causing the problem of out synching between Umbraco and Angular was due to the $http.get query which is asynchronous with Angular (no other choice I think) and after a response from the server to get a valid URL, the $scope object was not able to talk to Umbraco to redirect to the valid URL.
On my asp.net MVC controller, the GetUrl function was trying to get a valid URL doing a query to the database where I keep a structure of nodes which correspond to a tree displayed to the user. This is a slow process and the time required to respond to the HTTP get request was too long the vast majority of the time.
Here is my solution to this problem:
'use strict';
var myCompany = myCompany || {};
myCompany.myProject = myCompany.myProject || {};
myCompany.myProject.controller = (function (parent){
parent.urls = {};
function loadUrls () {
$.get('/umbraco/backoffice/administration/CustomSection/GetUrls')
.success(function (data) {
parent.urls = data;
});
};
loadUrls();
return parent;
})({});
angular.module("umbraco")
.controller('Administration.AdministrationTree.EditController', function administrationEditController($scope, $routeParams, $http) {
//set a property on the scope equal to the current route id
$scope.id = $routeParams.id;
$scope.url = "";
$scope.canShow = false;
$scope.showIframe = function () {
if ($scope.url === "") {
return false;
}
return true;
};
$scope.canShow = false;
if (!$scope.id) {
return;
}
var url = myCompany.myProject.controller.urls.find(function (element) {
return element.Key == $scope.id;
});
if (url) $scope.url = url.Value;
$scope.canShow = $scope.url;
});
Note in this case that I have an iffe function which query the server to build an array of all my URLs from the backoffice and then when Angular need a redirection, I search directly from the array.
The iffe function is calling only once when the user enters in the backoffice section which I think is nice because the structure behind rarely changes.
I'm not sure if it's a hack or the valid way to do the thing due to my lack of experience with Angular but it works like a charm.

Issues injecting Angular factories and services

I don't know what it is about injecting factories, but I am having the most difficult time.
I've simulated what I'm attempting to do via this sample plunk http://plnkr.co/edit/I6MJRx?p=preview, which creates a kendo treelist - it works fine.
I have an onChange event in script.js which just writes to the console. That's also working.
My plunk loads the following:
1) Inits the app module, and creates the main controller myCtrl (script.js)
2) Injects widgetLinkingFactory int myCtrl
3) Injects MyService into widgetLinkingFactory
The order in which I load the files in index.html appears to be VERY important.
Again, the above plunk is NOT the real application. It demonstrates how I'm injecting factories and services.
My actual code is giving me grief. I'm having much trouble inject factories/services into other factories.
For example,
when debugging inside function linking() below, I can see neither 'CalculatorService' nor 'MyService' services. However, I can see the 'reportsContext' service.
(function () {
// ******************************
// Factory: 'widgetLinkingFactory'
// ******************************
'use strict';
app.factory('widgetLinkingFactory', ['reportsContext', 'MyService', linking]);
function linking(reportsContext, MyService) {
var service = {
linkCharts: linkCharts
};
return service;
function linkCharts(parId, widgets, parentWidgetData) {
// *** WHEN DEBUGGING HERE, ***
// I CANNOT SEE 'CalculatorService' AND 'MyService'
// HOWEVER I CAN SEE 'reportsContext'
if (parentWidgetData.parentObj === undefined) {
// user clicked on root node of grid/treelist
}
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
// REFRESH HERE...
}
});
}
}
})();
A snippet of reportsContext'service :
(function () {
'use strict';
var app = angular.module('rage');
app.service('reportsContext', ['$http', reportsContext]);
function reportsContext($http) {
this.encodeRageURL = function (sourceURL) {
var encodedURL = sourceURL.replace(/ /g, "%20");
encodedURL = encodedURL.replace(/</g, "%3C");
encodedURL = encodedURL.replace(/>/g, "%3E");
return encodedURL;
}
// SAVE CHART DATA TO LOCAL CACHE
this.saveChartCategoryAxisToLocalStorage = function (data) {
window.localStorage.setItem("chartCategoryAxis", JSON.stringify(data));
}
}
})();
One other point is that in my main directive code, I can a $broadcast event which calls the WidgetLinking factory :
Notice how I'm passing in the widgetLinkingFactory in scope.$on. Is this a problem ?
// Called from my DataModel factory :
$rootScope.$broadcast('refreshLinkedWidgets', id, widgetLinkingFactory, dataModelOptions);
// Watcher setup in my directive code :
scope.$on('refreshLinkedWidgets', function (event, parentWidgetId, widgetLinkingFactory, dataModelOptions) {
widgetLinkingFactory.linkCharts(parentWidgetId, scope.widgets, dataModelOptions);
});
I am wasting a lot of time with these injections, and it's driving me crazy.
Thanks ahead of time for your assistance.
regards,
Bob
I think you might want to read up on factories/services, but the following will work:
var app = angular.module('rage')
app.factory('hi', [function(){
var service = {};
service.sayHi = function(){return 'hi'}
return service;
}];
app.factory('bye', [function(){
var service = {};
service.sayBye = function(){return 'bye'}
return service;
}];
app.factory('combine', ['hi', 'bye', function(hi, bye){
var service = {};
service.sayHi = hi.sayHi;
service.sayBye = bye.sayBye;
return service;
}];
And in controller...
app.controller('test', ['combine', function(combine){
console.log(combine.sayHi());
console.log(combine.sayBye());
}];
So it would be most helpful if you created a plunk or something where we could fork your code and test a fix. Looking over your services it doen't seem that they are returning anything. I typically set up all of my services using the "factory" method as shown below
var app = angular.module('Bret.ApiM', ['ngRoute', 'angularFileUpload']);
app.factory('Bret.Api', ['$http', function ($http: ng.IHttpService) {
var adminService = new Bret.Api($http);
return adminService;
}]);
As you can see I give it a name and define what services it needs and then I create an object that is my service and return it to be consumed by something else. The above syntax is TypeScript which plays very nice with Angular as that is what the Angular team uses.

Angularjs - how to watch for changes in DOM and apply a new style to it?

I have a very simple angular app that pushes data in without refreshing the page using setInterval. Now, how can I listen or watch for new data/changes, so that if the new value/data differ from the previous one a new css style will be applied to that particular new value (for example it will change the font color to red).
My code is below:
view:
<h1>{{title}}</h1>
<ul>
<li ng-repeat="friend in friends"><strong>Name: </strong>{{friend.name}} : {{friend.username}}</li>
</ul>
data:
angular
.module ('myApp')
.factory ('Friends', ['$http', function ($http) {
return {
get: function () {
return $http.get ('users.json').then (function (response) {
return response.data;
});
}
};
}]);
Controller:
angular
.module ('myApp')
.controller ('summaryCtrl', ['$scope', 'Friends', function ($scope, Friends) {
$scope.title = "Friends";
$scope.loadData = function () {
Friends.get ().then (function (data) {
$scope.friends = data;
});
};
//initial load
$scope.loadData();
var timer = setInterval(function(){
$scope.loadData();
},5000);
}]);
many thanks
Use $interval instead of setInterval, since it triggers a digest loop it will update your data automatically
angular
.module ('myApp')
.controller ('summaryCtrl', ['$scope', 'Friends', '$interval' function ($scope, Friends, $interval) {
$scope.title = "Friends";
$scope.loadData = function () {
Friends.get ().then (function (data) {
$scope.friends = data;
});
};
//initial load
$scope.loadData();
var timer = $interval(function(){
$scope.loadData();
},5000);
}]);
My recommendation would be to manually compare each friend item and assign a changeFlag whenever the data has changed.
To start, keep a reference to the old data and whenever new data comes in, compare the two, like this:
var oldData = undefined; // Somewhere in initialization.
...
Friends.get().then(function (response) {
var newData = response;
if (oldData && JSON.stringify(oldData) != JSON.stringify(newData))
{
$scope.friends = newData;
$scope.$apply(); // Force the entire page to be redrawn. You can do style bindings to change a style.
}
oldData = response;
}
This will get you half-way to your goal. You will only be refreshing the page whenever something has changed, but there is no indication as to which friend has changed. I imagine this is what you are attempting to accomplish. You want to highlight those friends that have changed.
To do this we could simply create a comparison function that applies a flag to each object that has changed. However, this code assumes that some property on each friend remains fixed. This is normally why an id property is given to each item in a database. I'm going to assume you have an id property for each friend that never changes regardless if their name, age, email, etc. does.
var changeFlagFriendsObjects = function(oldData, newData) {
var idToOldDataMap = {};
oldData.forEach(function (friend) {
idToOldDataMap[friend.id] = friend;
});
newData.forEach(function (friend) {
var oldFriendData = idToOldDataMap[friend.id];
friend.changeFlag = JSON.stringify(oldFriendData) != JSON.stringify(friend);
});
};
// You would call changeFlagFriendsObjects in the other example above. I'm sure this would be easy to figure out how to place.
Regarding binding styles in the HTML to properties, see here.
An example would be like the following:
<!-- Apply the 'highlight' style when changeFlag is true -->
<li ng-repeat="friend in friends" ng-style="highlight={changeFlag: true}"><strong>Name: </strong>{{friend.name}} : {{friend.username}}</li>

Angular Access scope data to factory?

I have a situation where i am getting data on scroll from a service. Now i need to filter data using popular data and latest post
Here is my service:
App.factory('Serviec', function ($http, $rootScope) {
var Hututoo = function () {
this.items = [];
this.busy = false;
this.after = 'Serviec_0';
};
Serviec.prototype.nextPage = function () {
if (this.busy) return;
this.busy = true;
// return undefined
console.log($rootScope.listtype);
$http.get(baseurl + 'ajax/gethome?after=' + this.after).success(function (data) {
var items = data;
for (var i = 0; i < 5; i++) {
this.items.push(items[i]);
// debugger;
}
this.after = "Hututoo_" + this.items.length;
this.busy = false;
}.bind(this));
};
return Serviec;
});
In controller:
$scope.data= new Serviec();
$scope.listtype= 'latest';
$scope.changelist = function(str){
$rootScope.listtype = str;
$scope.data.items=[];
$scope.data.after = 'Serviec_0';
$http.post(baseurl+"ajax/gethome","after="+$scope.hututoo.after+"&list="+str).success(function(data){
$scope.data.items = data;
});
}
Html
<li ng-click="expression = 'latest';changelist('latest');" ng-class="{latest_icon:expression == 'latest'}">Latest Hoot</li>
<li ng-click="expression = 'popular';changelist('popular');" ng-class="{popular_icon:expression == 'popular'}">Popular Hoots</li>
So with these click i need to order data .I have to make http call to get data according to user click.
I was thinking that i can make a scope data that define listing type and get it in factory.
How can i inject this scope in Serviec Factory. I have tried it using rootscope. initally list type is set to latest , but it shows undefined. So what would be the best method achieve this?
Update:
Now i can access scope data in angular service, but small issue comes here is on list click previous item's in scope doesn't get empty and new items get pushed into the scope.
So demand is on list click previous data become zero and new get pushed into the scope.
Pass the $rootScope to controller and set the listtype as required.
App.controller('MainCtrl', function($scope, $rootScope, Hututoo) {
$scope.hututoo = new Hututoo();
$scope.listtype= 'latest';
$scope.changelist = function(str){
$rootScope.listtype= str;
$scope.hututoo = new Hututoo();
$scope.hututoo.nextPage();
}
});
Plunker
Avoid using $rootScope -- it's bad practice, much like using the head object in pure JS. You're already able to share data between the factory and controller, so why not just make listtype a property of the factory:
var Hututoo = function () {
...
this.listtype = 'latest';
};
and use it in your controller as you are other properties:
$scope.changelist = function(str){
$scope.hututoo.listtype = str;
...
};
Demo <-- ajax requests don't work for obvious reasons
$scope is not available to inject in services however you can pass it using parameters like so.
app.factory('Hututoo', function ($resource) {
var somePrivateVar = [];
return {
set: function(scopeVar){
somePrivateVar.push(scopeVar);
},
get: function(){
return somePrivateVar;
}
}
});
then in controller
Hututoo.set($scope.anyVar);

Reusable components in angular controller

I am trying to create a reusable component for my controllers which can be used multiple times in different controllers.
See plunker: http://plnkr.co/edit/Lc4z4L?p=preview
The problem shown in the plunker is, that in the FirstCtrl the same message is shown than in the SecondCtrl.
How can I achieve some kind of isolated scope with the service?
Or am I using the wrong concepts?
While it's true a service only has a single instance, you can also return a function which you can then new in your controller which will give you an individual instance of that function:
app.service('alertService', function($timeout) {
return function () {
// assign this to service only because I'm lazy
var service = this;
var timeout;
// start with empty array holding the alerts.
service.alert_list = [];
// method to add an alert
// alert_obj is a object with members type = ( success | info | warning | danger )
// and msg which is the message string
service.addAlert = function (alert_obj) {
service.alert_list = [];
service.alert_list.push(alert_obj);
$timeout.cancel(timeout);
timeout = $timeout(service.clearAlerts, 5000);
};
service.clearAlerts = function clearAlerts() {
service.alert_list = [];
};
}
});
Your updated controller would now look like this:
app.controller('SecondCtrl', function($scope, alertService, $timeout) {
$scope.alertService = new alertService();
$scope.alertService.addAlert({"type": "info", "msg": "Infomessage II"});
$scope.name = 'World II';
});
Updated plunker: http://plnkr.co/edit/RhJbbxj4XxdwY6GAest9?p=preview

Resources