No Permission error using Firebase - angularjs

I am trying to add Firebase for the first time to an ionic application. I have set up my project and referenced the javascript files however when I run the application I see the error 'Error: Permission Denied'
I have not yet set up authentication in my app but, if I am understanding things properly I shouldn't need to do this while I am just testing.
My index.html contains the following:
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- Firebase -->
<script src="https://cdn.firebase.com/js/client/2.2.4/firebase.js"></script>
<!-- AngularFire -->
<script src="https://cdn.firebase.com/libs/angularfire/1.2.0/angularfire.min.js"></script>
While the app.js has the following lines:
angular.module('starter', ['ionic', 'firebase'])
.factory("Items", function($firebaseArray) {
var itemsRef = new Firebase("https://todo-83e58.firebaseio.com/items");
return $firebaseArray(itemsRef);
})
.controller('ListCtrl', function($scope, $ionicListDelegate, Items) {
$scope.items = Items;
$scope.addItem = function () {
var name = prompt("what do you need to buy?");
if (name) {
$scope.items.$add({"name": name});
}
};
I would be grateful for any pointers on how to get the basics right as I have tried following the information on the Firebase site and I seem to have it all set up correctly. Am I misunderstanding the authentication or shouldI be able to write to the database without setting this up first ?

It sounds that your Security & Rules isn't giving you access to items. Please make sure to spend some time reading the S&R documentation.
If you are only testing the application and don't want to care about it now just set it to full read and write.
On the new console go to Database > Rules.
{
"rules": {
".read": true,
".write": true
}
}

Related

AngularFire error - Client doesn't have permission to access the desired data [duplicate]

This question already has answers here:
Firebase chat app setValue failed error with a public database?
(2 answers)
Closed 4 years ago.
This is my first try at getting angularjs to talk to firebase.
I have setup the firebase database in test mode so there is no auth but i keep getting an error
Controller code is
.controller('FaqsCtrl', ['$scope', '$firebaseArray', '$uibModal', function($scope, $firebaseArray, $modal, $filter) {
var ref = firebase.database().ref().child("faq");
$scope.faqs = $firebaseArray(ref);
}])
JS links as follow
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-route.min.js"></script>
<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/5.5.4/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.5.4/firebase-database.js"></script>
<!-- AngularFire -->
<script src="https://cdn.firebase.com/libs/angularfire/2.3.0/angularfire.min.js"></script>
Firebase rules are
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Error is - Error: permission_denied at /faq: Client doesn't have permission to access the desired data.
Everything I have found on the web seems to be for an older version of Firebase
Go to Firebase console of your app
Select Database From Side Menu --> Select Rule From tabs above --> Update your rule like this.
{
"rules": {
".read": true,
".write": true
}
}
hope it solve your problem.

Adding Google Analytics to React

I am trying to add Google Analytics to a React Web Application.
I know how to do it in HTML/CSS/JS sites and I have integrated it in an AngularJS app too. But, I'm not quite sure how to go about it when it comes to react.
With HTML/CSS/JS, I had just added it to every single page.
What I had done with AngularJS was adding GTM and GA script to index.html and added UA-labels to the HTML divs (and buttons) to get clicks.
How can I do that with React?
Please help!
Update: Feb 2019
As I saw that this question is being searched a lot, I decided to expand my explanation.
To add Google Analytics to React, I recommend using React-GA.
Add by running:
npm install react-ga --save
Initialization:
In a root component, initialize by running:
import ReactGA from 'react-ga';
ReactGA.initialize('Your Unique ID');
To report page view:
ReactGA.pageview(window.location.pathname + window.location.search);
To report custom event:
ReactGA.event({
category: 'User',
action: 'Sent message'
});
More instructions can be found in the github repo
The best practice for this IMO is using react-ga.
Have a look at the github rep
If you prefer not to use a package this is how it can work in a react application.
Add the "gtag" in index.html
<!-- index.html -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "<GA-PROPERTYID>");
</script>
In the submit action of the login form, fire off the event
window.gtag("event", "login", {
event_category: "access",
event_label: "login"
});
Without using a package this is how I would do it:
In your index.js (in the render method):
{/* Global site tag (gtag.js) - Google Analytics */}
<script
async
src="https://www.googletagmanager.com/gtag/js?id=YOUR_TRACKING_ID"
/>
<script>{injectGA()}</script>
And outside the class:
const injectGA = () => {
if (typeof window == 'undefined') {
return;
}
window.dataLayer = window.dataLayer || [];
function gtag() {
window.dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'YOUR_TRACKING_ID');
};
One other great library that you can check is redux-beacon.
It gets integrated very easily with react/redux application and has a great documentation for it. ReactGA is good too but with redux-beacon, you won't clutter your app code with google analytics code as it works via its own middleware.
Escape the analytics code with dangerouslySetInnerHTML
First you have of course to share the header code to all pages, e.g. as asked at: React js do common header
Then, this Next.js answer https://stackoverflow.com/a/24588369/895245 gives a good working code that should also work outside of Next.js. It escapes the analytics code with dangerouslySetInnerHTML:
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-47867706-3"></script>
<script
dangerouslySetInnerHTML={{
__html: `window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-47867706-3', { page_path: window.location.pathname });
`,
}}
/>
where you should replace UA-47867706-3 with your own code.
This code is exactly the code that Google gives, but with the following modification: we added the:
{ page_path: window.location.pathname }
to gtag('config' for it to be able to get the visited path, since this is a JavaScript SPA.
This generates the desired output on the browser:
<script async="" src="https://www.googletagmanager.com/gtag/js?id=UA-47867706-3"></script><script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-47867706-3', { page_path: window.location.pathname });
</script>
The only other divergence from the exact code given by Google is the async="" vs async, but both of those are equivalent in HTML since it is a boolean attribute, see also: What's the proper value for a checked attribute of an HTML checkbox?
Escaping with dangerouslySetInnerHTML is necessary because otherwise React interprets the code inside script a JSX and that fails with:
Syntax error: Unexpected token, expected "}"
21 | <script>
22 | window.dataLayer = window.dataLayer || [];
> 23 | function gtag(){dataLayer.push(arguments);}
| ^
24 | gtag('js', new Date());
25 |
26 | gtag('config', 'UA-47867706-3');
I wish they would just automatically escape stuff inside script for us.
Finally to get page switches, you also have to track that with more code, see the Next.js answer mentioned above for an example.
Related: Adding script tag to React/JSX
Tested on react 17.0.2, next.js 10.2.2.
There are 2 types of Google Analytics properties: Universal Analytics (UA-xxxxxxxxx-x) which is deprecated with the end of life on 2023.07.01 and Google Analytics 4 property (G-xxxxxxxxxx) which is the replacement.
react-ga was popular for Universal Analytics but the maintainer doesn't plan to update it (related issues: 1, 2, 3) and it had maintenance issues (1). react-ga4 and ga-4-react popped up as replacements but since these are similar wrappers you're at the mercy of the maintainers to implement and support all functionality.
The simplest way to get started is to follow Google's guide: include gtag on the page and use it as window.gtag. This method works for both old and new tags and there's even TypeScript support via #types/gtag.js. The script can be loaded async as recommended.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<!-- ... -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-xxxxxxxxxx" >
</script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-xxxxxxxxxx')
</script>
<!-- ... -->
</head>
<body>
<!-- ... -->
</body>
</html>
Keep in mind that Google Analytics does automatic page tracking, but this will not work for every use case. For example, hash and search parameter changes are not tracked. This can lead to a lot of confusion. For example, when using HashRouter or anchor links the navigation will not be tracked. To have full control over page view tracking you can disable automatic tracking. See for a detailed explanation: The Ultimate Guide to Google Analytics (UA & GA4) on React (Or Anything Else
Manual page tracking: https://stackoverflow.com/a/63249329/2771889
You can see this working in cra-typescript-starter where I'm also setting the tag from an env var.
I suggest embedding the Segment script into your index.html, use the analytics library that is accessible on the window object, and add tracking calls onto React’s event handlers:
export default class SignupButton extends Component {
trackEvent() {
window.analytics.track('User Signup');
}
render() {
return (
<button onClick={this.trackEvent}>
Signup with Segment today!
</button>
);
}
}
I’m the maintainer of https://github.com/segmentio/analytics-react. I recommend checking it out if you want to solve this problem by using one singular API to manage your customer data, and be able to integrate into any other analytics tool (we support over 250+ destinations) without writing any additional code. 🙂
Looking at google's site https://developers.google.com/analytics/devguides/collection/analyticsjs,
you could also add Google Analytics using this function:
const enableGA = () => {
!function(A,n,g,u,l,a,r){A.GoogleAnalyticsObject=l,A[l]=A[l]||function(){
(A[l].q=A[l].q||[]).push(arguments)},A[l].l=+new Date,a=n.createElement(g),
r=n.getElementsByTagName(g)[0],a.src=u,r.parentNode.insertBefore(a,r)
}(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXXXXX-X');
ga('send', 'pageview');
}
This way you don't need an external library, and it's pretty quick to setup.

AngularJS error [$injector:unpr] Unknown provider: in IE11

I couldn't find help in Google or here either. I'm new to Angular and I'm facing this error only in IE11 and below.
The error I'm getting is this:
My IE is in Portuguese so the translate of the first error is: it's not possible to get property of "getAttribute" of undefined or null
this is my app.config.js file
// Checking if an optional module is registered.
// If it's not, register an empty one to prevent errors.
(function(optDeps){
optDeps.forEach(function(dep){
try{
angular.module(dep);
}catch(e){
angular.module(dep, []);
}
})
})(['ui.carousel', 'ui.mask', 'vAccordion', 'ngAnimate']);
angular
.module('poletto', [
// Third party
'smoothScroll',
'ui.carousel',
'ui.mask',
'vAccordion',
'ngAnimate',
// Components
'poletto.components',
// Controllers
'poletto.controllers',
// Directives
'poletto.directives',
// Factories
'poletto.factories',
// Filters
'poletto.filters',
// Services
'poletto.services'
])
.constant('CONSTANTS', {
BASE_URL: document.currentScript.getAttribute('data-base-url')
})
.config(function($httpProvider){
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
})
.config(function($locationProvider){
if(window.history.pushState){
$locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: false });
}
})
// Extending JQLite with a function that find nodes by className
.run(function(){
angular.element.prototype.findBySelector = function(selector){
var matches = [];
for(key in this){
// Pushing only HTMLElement's
if(this[key].nodeType){
// NodeList to array
var results = Array.prototype.slice.call(this[key].querySelectorAll(selector));
matches.push.apply(matches, results);
}
}
return angular.element(matches);
};
})
I've searched google and tried some solutions such as:
add <meta http-equiv="X-UA-Compatible" content="IE=11" />
wrap all my declarations in:
(function (angular) {
"use strict";
//code
}(window.angular));
add this in html tag:
<html lang="pt-br" xmlns:ng="http://angularjs.org">
Also I couldn't find any angular polyfills neither src/ folder, which I saw in a similar question with angular 2.
I don't know which file I should put here, so if you need some more info, you can ask me and I update the question.
Unfortunately document.currentScript is not supported on IE and can't be polyfilled so it can't done that way. Perhaps, you can embed the base url somewhere else or maybe add an id to your script and retrieve it in old school javascript.
<script id="main" data-base-url="https://my-api.com"></script>
And then retrieve it like this:
var currentScript = document.getElementById('main');
In your CONSTANTS provider you can do something like this:
.constant('CONSTANTS', {
BASE_URL: document.getElementById('main').getAttribute('data-base-url')
})
The problem stems from using document.currentScript, which isn't supported in IE 11 and apparently can't be polyfilled (easily at least). So you'll have to find a different way to declare your BASE_URL constant.

Migrating Firebase 2.x to 3.4.1 AngularJS For Google OAuth

I am new to Angular & Firebase. I am currently developing an Ionic app. Somehow I came to know that, to use Firebase, I need to set up authentication system (I prefer Google).
It was not easy to integrate the code into AngularJS which were mentioned in official Firebase website. So I just picked up someone's working code and replaced his Firebase database URL to mine, I could get it done. But it was a mistake.
This is the unchanged code and his output (which is working as expected).
index.html
<script src="lib/angularfire/dist/angularfire.min.js"></script>
<script src="lib/firebase/firebase.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
app.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services', 'firebase'])
.constant('FirebaseUrl', 'https://ionicle.firebaseio.com/')
.service('rootRef', ['FirebaseUrl', Firebase])
So first, I removed his Firebase URL to add mine and got this error:
We have detected that you are using the v2.x or lower authentication SDKs with a project that was created at console.firebase.google.com. You must use the 3.0.0 or greater authentication SDKs with projects that have been created in the new console.
Then I updated firebase.js file to 3.4.1 version. Then I got a Reference error in browser's Dev console: ReferenceError: Firebase is not defined
.service('rootRef', ['FirebaseUrl', Firebase])
So what I finally need is a working Google OAuth with Firebase 3.x and AngularJS.
Although you didn't provide enough examples of your code (dependency injection is not enough), I think that the main problem you are having is that you are using old examples of the code with the new Firebase version.
Things like this:
var app = angular.module('app', ['firebase']);
app.controller('Ctrl', function($scope, $firebaseAuth) {
var ref = new Firebase('https://...');
$scope.authObj = $firebaseAuth(ref);
...
});
are changed into this:
var app = angular.module('app', ['firebase']);
app.controller('Ctrl', function($scope, $firebaseAuth) {
var config = {
apiKey: "***",
authDomain: "***.firebaseapp.com",
databaseURL: "https://***.firebaseio.com",
storageBucket: "***.appspot.com",
messagingSenderId: "***"
};
firebase.initializeApp(config);
$scope.authObj = $firebaseAuth(firebase.auth());
...
});
Then on that authObj you can add a provider for the client you want to use to authenticate (Google/GitHub/Facebook...):
var provider = new firebase.auth.GoogleAuthProvider();
$scope.authObj.$signInWithPopup(provider).then(function(result) {
console.log(result);
});
Keep in mind that you must enable Authentication with Google (or any other provider) in your Firebase console. For detailed instructions please check this link.

angularJS module bootstrap issues angular-appinsights

Hoping someone can help me out here... We are new to angularJS but have committed to using it on an upcoming project. One of the things we want to get in place from the start is app feature usage monitoring and we are planning to use Microsoft's Application Insights to do that. I was very happy to discover that there is an angularJS module already built for working with app insights recommended on Microsoft's getting started page for App Insights angular-appinsights. Unfortunately we are having a very difficult time bootstrapping this module.
Pretty sure we are the problem here, I feel that if we knew a little more about angularJS we could figure this out but since we are just cutting our teeth on it I am turning to SO for help!
So here is the portion of index.html where we are loading all of our scripts:
<!-- 3rd party libraries -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-route.min.js"></script>
<script src="scripts/angular-local-storage.min.js"></script>
<script src="scripts/loading-bar.min.js"></script>
<script src="scripts/angular-appinsights.js"></script>
<!-- Load app main script -->
<script src="app/app.js"></script>
Here is the relevant portion of app.js where everything is wired up:
var app = angular.module('MTCAPITester', ['ngRoute', 'LocalStorageModule', 'angular-loading-bar','angular-appinsights']);
app.config(['$routeProvider','insightsProvider',function ($routeProvider,insightsProvider) {
$routeProvider.when("/home", {
controller: "homeController",
templateUrl: "/app/views/home.html"
});
$routeProvider.when("/login", {
controller: "loginController",
templateUrl: "/app/views/login.html"
});
$routeProvider.otherwise({ redirectTo: "/home" });
insightsProvider.start('our app insights key here');}]);
And here is the app insights javascript that you are supposed to put in the head tag of index.html:
<script type="text/javascript">
var appInsights = window.appInsights || function (config) {
function s(config) { t[config] = function () { var i = arguments; t.queue.push(function () { t[config].apply(t, i) }) } } var t = { config: config }, r = document, f = window, e = "script", o = r.createElement(e), i, u; for (o.src = config.url || "//az416426.vo.msecnd.net/scripts/a/ai.0.js", r.getElementsByTagName(e)[0].parentNode.appendChild(o), t.cookie = r.cookie, t.queue = [], i = ["Event", "Exception", "Metric", "PageView", "Trace"]; i.length;) s("track" + i.pop()); return config.disableExceptionTracking || (i = "onerror", s("_" + i), u = f[i], f[i] = function (config, r, f, e, o) { var s = u && u(config, r, f, e, o); return s !== !0 && t["_" + i](config, r, f, e, o), s }), t
};
window.appInsights = appInsights;
</script>
Unfortunately we consistently get the ugly angular modulerr which I assume is telling me it can't bootstrap this module b/c if I remove the code related to this module everything works fine.
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.16/$injector/modulerr?p0=MTCAPITester&p1=Er…gleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.2.16%2Fangular.min.js%3A32%3A445)
Can anyone help me understand what we are missing here? I don't quite understand where the reference to insightsProvider is coming into play as I don't have that defined anywhere and I don't see it defined in his library either.
Any help with this would be greatly appreciated, this seems pretty straight forward but I am just not comfortable enough with angularJS at this point to understand where/why this is failing...
Another issue I've found with 'angular-appinsights.js' is, If you are using the ngRoute directive in your angular application for routing, then you should be okay. But if you are using ui.router for routing/states then 'angular-appinsights.js' will not work correctly and will throw an error. I found a fix for this here Angular-AppInsights – Unknown Provider – FIX, and its quite simple. In the .run function of the angular-appinsights.js module, you will find $route is being injected. If you remove $route from being injected into that function, angular-appinsights will work.
Turns out that the MS provided JS that they instruct you to put in the head tag of index.html was the source of the problem. Sperr speculated that maybe it was run before angular was loading. Solution to the problem was to pull that js out of the head tag and put it in its own .js file, then include it below the reference to angular-appinsights.js. With that change, everything is working great.

Resources