How to disable firebase 3-way data binding - angularjs

I am using angularJS 1.3 with angularfire and firebase.
I did create some factories that encapsulate the firebase object, and it works very well. The 3 way data binding is really cool.
I am planning to build a large application using firebase for data persistance, but I am facing a massive issue :
In my business model, I want some models/collections to support 3-way data binding, but I want other collections not to be updated live.
Some clients visiting the resulting website might be scared when they see the website's content being updated live - and I don't want that.
Imagine you are reading an article , somehow long and complexe, and you put your attention into a paragraph which you have issues understanding, and suddenly, the paragraph disappears and is replaced by a new one. Now imagine that you have no idea about web development. You might start to think to consult some professionnal about your mental health, or think your computer is hacked. Who knows !
So I would like to disable the 3 way data binding for this article, and avoid this border-line client phone calls. The only solution I found would be not to use fireangular, and use the beyond angularfire documentation section instead, and remove the following lines :
ref.on("value", function(snapshot) {
$timeout(function() {
$scope.data = snapshot.val();
});
});
This would fix the issue, but then in my admin interface, I would have to implement a second Factory so admin users can access the 3 way data binding for articles - Which is not very DRY.
In my artitcle controller, I would have to write something like this :
$scope.loadArticle = function(){
if(UserService.type === 'admin'){
AdminArticleFactory.get(id);
}
else{
ArticleFactory.get(id);
}
}
Is there any other way of setting up firebase to disable the pull updates?

Yeah, that is what I also ran into. Sometimes you will repeat yourself with Firebase. Also when storing data. I would recommend just making a function to save the data that you don't want to be updated instantly.
<button ng-click="saveChanges">save</button>
In controller
$scope.saveChanges = function () {
var obj = $firebaseObject(ref);
obj.foo = "bar";
obj.$save().then(function(ref) {
ref.key() === obj.$id; // true
}, function(error) {
console.log("Error:", error);
});
}
edit
To desync a firebase object/array you can follow this answer: How to disassociate angularFire bound object?

Related

AngularFire - Get a firebaseObject for each item in a firebaseArray ng-repeat

I have an ng-repeat which is connected to a firebaseArray which is an index of a user's doc Ids.
I want to display a list of their docs with additional info for each one, e.g. it's title and description.
My firebase structure is:
+users
- userId1
-theirDocs
-docId1: true
-docId2: true
+docs
-docId1
- tile
- description
- url
-docId2
- etc etc
I've tried everything and still can't get this to work, it seems a pretty common use case. I've tried using a function that calls a firebaseObject each time. I've tried using a separate controller. I've tried a directive, I've even tried using firebase.utils library (I think out of date now).
Can anyone recommend the best way to do this using AngularFire? Thanks in advance!
It would be better to see a code snippet as to fully understand what you've tried first of all, as it's difficult to determine where the issues lie. That being said, as long as your rules are not preventing this, you may need to wait for the data to download using $loaded function beforehand.
EXAMPLE
This example is clearly available by following this link, yet here is an example for further clarity:
var yourFirebaseReference = firebase.database().ref("REPLACE WITH YOUR FIREBASE BRANCH HERE");
var data = $firebaseArray(yourFirebaseReference);
data.$loaded().then(function(x) {
console.log(data) // Example, you can do what you want with your 'data' now as the data has loaded
x === data; // true
}).catch(function(error) {
console.log("Error:", error);
});

how can I fetch this data to html page using angular.js?

var gamedataRef = firebase.database().ref('gamedata');
gamedataRef.on('child_added', function(data) {
$scope.abc = data.val().textgame;
});
I have to find this.
Firebase data is loaded asynchronously. This is great, because it allows the browser to continue being responsive while the data is being loaded. But unfortunately it also means that AngularJS is not expecting updates anymore by the time the data comes back.
The solution is to tell AngularJS when the data comes back, with for example $timeout():
var gamedataRef = firebase.database().ref('gamedata');
gamedataRef.on('child_added', function(data) {
$timeout(function(){
$scope.abc = data.val().textgame;
});
});
You might also want to have a look at AngularFire, an open-source binding library that solves this problem and a lot of others you're likely to run into.

How do I implement the C in CRUD with AngularJS, components, and ngResource?

I'm quite new to Angular, and I'm adapting a simple CRUD app written using standard controllers and ngResource to use the components introduced in 1.5. None of the docs and resources I've found so far discuss how to:
create a new item from scratch
integrate with ngResource
so I'm wondering if anyone can give some pointers on how best to proceed.
My existing app has a simple factory declaring a resource entity, and a single controller that
instantiates a new instance of the resource: $scope.newEntity = new Entity();
populates the $scope with a list of the resources retrieved from the backend: Entity.query(function (data) { $scope.entities = data; });
provides a couple of functions for deleting, updating, and saving the resource to the backend.
In the HTML I have a form that works with $scope.newEntity and the controller saving method to save the new entity to the backend. I also have an ng-repeat that lists the entries stored in $scope.entities, with a couple of additional ng-clicks to perform some editing and deleting.
What I want to do now is implement some inline editing in the list. I know I can do this with my existing approach, but I want to cleanly reuse the form validation functionality I have in the existing entity creation form in the entity editing code, without duplicating. Components seem like a natural fit for that to my (admittedly inexperienced) eyes.
With the component-based approach, I have followed the documentation at https://docs.angularjs.org/guide/component under Example of a component tree, and created an entity-list and entity-detail component. These work okay so far, and I think I can figure out how to wire up the on-delete and on-update events. What I can't figure out is how to approach an on-create event.
Should I use a completely separate controller with my existing simple form to handle the creation event? If so, how can I get the existing list to automatically update? Will that creation event propagate across to the list controller?
Or am I missing something in the existing list controller? Or is the entity creation a special case for the detail controller?
I'm looking specifically for information about how to implement this using Angular components and ngResource, as I'd also like to be ready for Angular 2. Unless components and resources aren't meant to work together please don't post answers about how to achieve this using a completely different approach, or how to reuse HTML code without components. Thanks!
Actually the C in CRUD is realy simple. You were probably expecting an on-create method to be used from your entity-detail. entity-list should take care of the creation of the details however.
Here is the working code
I extended the example from the guide https://docs.angularjs.org/guide/component under Example of a component tree you were reading too and added the create:
(function () {
'use strict';
angular
.module('componentCrud')
.component('heroList', {
templateUrl: "component/hero-list.component.html",
controller : [
HeroListController
]
});
function HeroListController() {
var ctrl = this;
ctrl.list = createHeroes();
ctrl.updateHero = updateHero;
ctrl.deleteHero = deleteHero;
ctrl.createHero = createHero;
function createHero(){
ctrl.list.push({
name : 'Crazy Newling',
location: 'Morgues'
})
}
function updateHero(hero, prop, value) {
hero[prop] = value;
}
function deleteHero(hero) {
var idx = ctrl.list.indexOf(hero);
if (idx >= 0) {
ctrl.list.splice(idx, 1);
}
}
function createHeroes() {
return [{
name : 'Superman',
location: ''
},
{
name : 'Batman',
location: 'Wayne Manor'
}
]
}
}
})();
Then in HTML you just add a create button:
<b>Heroes</b><br>
<hero-detail ng-repeat="hero in $ctrl.list"
hero="hero"
on-delete="$ctrl.deleteHero(hero)"
on-update="$ctrl.updateHero(hero, prop, value)"></hero-detail>
<button ng-click="$ctrl.createHero()">Hire a new Hero</button>
I hope it is going to help you!

How to reload the ionic view?

I have created a sidemenu based app, in that after login I am displaying a number of tasks. If I click on the task it will redirect to the task details page, in that page I can update the tasks.
So after updating a task I need to go back to the previous task list page. I am using $ionicHistory.goBack(); to go back.
My problem is after come back, I need to refresh the task list i.e. updated task should not be there in the task list. How can I refresh/reload the task list?
If you bind your task to a tasks array, which will be used in the task list page, it should be automatically updated.
But the question is about not displaying, newly added tasks (still my previous suggestion should work) if not, performance reasons ionic views are cached, So when you come back to the previous view it doesn't go through the normal loading cycle. But you 2 options
1 - disable the caching by using <ion-view cache-view="false" view-title="My Title!"> in your ion-view, but this is not a very elegant solution. read more
2 - use ionRefresher (my preferred). read more here
https://github.com/angular-ui/ui-router/issues/582
according to #hpawe01 "If you are using the current ionicframework (ionic: v1.0.0-beta.14, angularjs: v1.3.6, angular-ui-router: v0.2.13), the problem with the not-reloading-controller could be caused by the new caching-system of ionic:
Note that because we are caching these views, we aren’t destroying scopes. Instead, scopes are being disconnected from the watch cycle. Because scopes are not being destroyed and recreated,controllers are not loading again on a subsequent viewing.
There are several ways to disable caching. To disable it only for a single state, just add cache: false to the state definition.
This fixed the problem for me (after hours of reading, trying, frustration).
For all others not using ionicframework and still facing this problem: good luck!"
Hope this helps.
You can also listen to ionic events such as $ionicView.enter on $scope and trigger the code that refreshes the list if you haven't bound your list as #sameera207 suggested.
EG:
// List.controller.js
angular.module('app')
.controller('ListController', ['$scope', function($scope) {
// See http://ionicframework.com/docs/api/directive/ionView/ for full events list
$scope.$on('$ionicView.enter', function() {
_someCodeThatFetchesTasks()
.then(function(tasks) {
$scope.tasks = tasks;
});
});
});
Bear in mind that it's not the most proper way (if proper at all) and if you do this you certainly have a design flaw. Instead you should share the same data array via a factory or a service for example.
For your task you can also use ion-nav-view.
It is well documented. And if you are using now Ionic 2 beta you can use some of the view lifecyle hooks like onPageWillLeave() or onPageWillEnter(). I just faced the same problem and defined a refresh() function, but the user had to click on a button to actually update the view. But then I found:
https://webcake.co/page-lifecycle-hooks-in-ionic-2/
You just have to import the Page and NavController module and also define it in the constructor. The you can use for example onPageWillEnter(), which will always invoke when you go again to a view:
onPageWillEnter() {
// Do whatever you want here the following code is just to show you an example. I needed it to refresh the sqlite database
this.storage.query("SELECT * FROM archivedInserates").then((data) = > {
this.archivedInserates =[];
if (data.res.rows.length > 0) {
for (var i = 0; i < data.res.rows.length; i++) {
this.archivedInserates.push({userName:data.res.rows.item(i).userName, email:
data.res.rows.item(i).email});
}
}
},(error) =>{
console.log("ERROR -> " + JSON.stringify(error.err));
});
}
With ionic beta 8 the lifecylcle events changed their names. Check out the official ionic blog for the full list of the lifecycle events.
if you are building data driven app then make sure use $ionicConfigProvider.views.maxCache(0);in your app.config so that each review can refresh for more details read this http://ionicframework.com/docs/api/provider/$ionicConfigProvider/

Update Angular View after resource post

Here is my problem! I use $resource API to post data from the client side to the server side. After the server side successfully updates the database, I kinda hope my data in view will be updated.
I chose to achieve this with:
$scope.magazines = Magazines.query();
$scope.addMagazine = function() {
var magazine = new Magazines({...payload data});
Magazines.save(magazine, function() {
$scope.magazines = Magazines.query();
});
};
Magazines is a defined ngResrouce factory.
This code works fine. My only problem is, whenever I activate this function (through mouseclick), the view flashes (refreshes) once. It is a really really bad user experience.
I wonder if there is any other way to add the new "magazine" to the scope without refreshing the entire $scope.magazines ?
By the way, the api at the backend will add a few properties (like created time, or id to it). Even if I write code to get the last added item (a different factory method I suppose), I'll still have to add it to the $scope.magazines and I don't know how to do that.
Any thought?
Just push the new Magazine onto the existing $scope.magazines (assuming it's an Array)
var magazine = new Magazines({...payload data});
$scope.magazines.push(magazine);

Resources