Emily Emily - 27 days ago 8
HTML Question

Why is this Reference Error appearing? (Cordova plugin, Facebook, Javascript, HTML)

I'm trying to integrate a "Log in with Facebook" option into my Cordova app. I'm writing in HTML, CSS and Javascript, and wish to deploy the finished app to Android and iOS. I'm currently testing on my Android phone and while my app was working correctly, it began to show this error when trying to integrate the Facebook login:

Uncaught ReferenceError: CordovaFacebook is not defined


I'm also integrating Firebase into my app - I'm using their sample chat application code here: https://gist.github.com/puf/8f67d3376d80ed2d02670d20bfc4ec7d (I've replaced my Firebase values in the below code with dummy values).

I'm using the
cordova-plugin-facebook 0.2.2 "CordovaFacebook"
plugin (https://github.com/bisrael/cordova-plugin-facebook). This is my current HTML:

<html>
<head>
<script src="https://www.gstatic.com/firebasejs/3.0.0/firebase.js"></script>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<title>ZeroToApp</title>
<style>
#messages { width: 40em; border: 1px solid grey; min-height: 20em; }
#messages img { max-width: 240px; max-height: 160px; display: block; }
#header { position: fixed; top: 0; background-color: white; }
.push { margin-bottom: 2em; }
@keyframes yellow-fade { 0% {background: #f2f2b8;} 100% {background: none;} }
.highlight { -webkit-animation: yellow-fade 2s ease-in 1; animation: yellow-fade 2s ease-in 1; }
</style>
<script>

// Issue seems to be CordovaFacebook isn't defined? but it does exist in the correct subfolder... maybe it's not initialized correctly?

function logInWithFacebook(){
CordovaFacebook.login({
permissions: ['email', 'user_likes'],
onSuccess: function(result) {
if(result.declined.length > 0) {
alert("The User declined something!");
}
/* ... */
},
onFailure: function(result) {
if(result.cancelled) {
alert("The user doesn't like my app");
} else if(result.error) {
alert("There was an error:" + result.errorLocalized);
}
}
});
}

document.addEventListener('DOMContentLoaded', function() {
// Step 0: HTML defined, variables for elements
var messagesList = document.getElementById('messages'),
textInput = document.getElementById('text'),
sendButton = document.getElementById('send'),
login = document.getElementById('login'),
googleLogin = document.getElementById('google'),
facebookLogin = document.getElementById('facebook'),
signedIn = document.getElementById('loggedin'),
logout = document.getElementById('logout'),
usernameElm = document.getElementById('username'),
password = document.getElementById('password'),
username = "Web";

var config = {
apiKey: "MyapiKey",
// authDomain: "MyauthDomain",
databaseURL: "MydatabaseURL",
storageBucket: "MystorageBucket",
messagingSenderId: "123456789"
};

// Get the Firebase app and all primitives we'll use
var app = firebase.initializeApp(config),
database = app.database(),
auth = app.auth(),
storage = app.storage();

var databaseRef = database.ref().child('chat');
sendButton.addEventListener('click', function(evt) {
var chat = { name: username, message: textInput.value };
databaseRef.push().set(chat);
textInput.value = '';
});
// Listen for when child nodes get added to the collection
databaseRef.on('child_added', function(snapshot) {
// Get the chat message from the snapshot and add it to the UI
var chat = snapshot.val();
addMessage(chat);
});

// Show a popup when the user asks to sign in with Google
googleLogin.addEventListener('click', function(e) {
auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
});
// Allow the user to sign out
logout.addEventListener('click', function(e) {
auth.signOut();
});
// When the user signs in or out, update the username we keep for them
auth.onAuthStateChanged(function(user) {
if (user) {
setUsername(user.displayName);
}
else {
// User signed out, set a default username
setUsername("Web");
}
});

function handleFileSelect(e) {
var file = e.target.files[0];
// Get a reference to the location where we'll store our photos
var storageRef = storage.ref().child('chat_photos');

// Get a reference to store file at photos/<FILENAME>.jpg
var photoRef = storageRef.child(file.name);
// Upload file to Firebase Storage
var uploadTask = photoRef.put(file);
uploadTask.on('state_changed', null, null, function() {
// When the image has successfully uploaded, we get its download URL
var downloadUrl = uploadTask.snapshot.downloadURL;
// Set the download URL to the message box, so that the user can send it to the database
textInput.value = downloadUrl;
});
}
file.addEventListener('change', handleFileSelect, false);
function setUsername(newUsername) {
if (newUsername == null) {
newUsername = "Web";
}
console.log(newUsername);
username = newUsername;
var isLoggedIn = username != 'Web';
usernameElm.innerText = newUsername;
logout.style.display = isLoggedIn ? '' : 'none';
facebookLogin.style.display = isLoggedIn ? 'none' : '';
googleLogin.style.display = isLoggedIn ? 'none' : '';
}
function addMessage(chat) {
var li = document.createElement('li');
var nameElm = document.createElement('h4');
nameElm.innerText = chat.name;
li.appendChild(nameElm);
li.className = 'highlight';
if ( chat.message.indexOf("https://firebasestorage.googleapis.com/") == 0
|| chat.message.indexOf("https://lh3.googleusercontent.com/") == 0
|| chat.message.indexOf("http://pbs.twimg.com/") == 0
|| chat.message.indexOf("data:image/") == 0) {
var imgElm = document.createElement("img");
imgElm.src = chat.message;
li.appendChild(imgElm);
}
else {
var messageElm = document.createElement("span");
messageElm.innerText = chat.message;
li.appendChild(messageElm);
}
messagesList.appendChild(li);
li.scrollIntoView(false);
sendButton.scrollIntoView(false);
}
//window.app = app; // NOTE: just for debugging
//for (var i=0; i < 10; i++) addMessage({ name: "Web", message: ''+i });
setUsername('Web');
});
</script>
</head>
<body>
<div id="fb-root"></div>
<div id='header'>
<label for='username'><img src="https://www.gstatic.com/images/icons/material/system/1x/account_box_black_24dp.png" width="24"/></label>
<span id='username'></span>
<span id='login'>
<button id='google' class='idp-button'>Sign in with Google</button>
<button id='facebook' class='idp-button'>Sign in with Facebook</button>
</span>
<button id='logout' class='idp-button'>Sign out</button>
</div>
<div class="push"></div>
<ul id='messages'></ul>
<div id='footer'>
<img src="https://www.gstatic.com/images/icons/material/system/1x/add_a_photo_black_24dp.png" width="24" onClick="logInWithFacebook();"/>
<input type="file" id="file" name="file" />
<input id='text'></input>
<button id='send'>Send</button>
</div>
</body>
</html>


Notes:


  • I have logInWithFacebook(); set to run on click of an image for testing purposes.

  • I've commented out the "authDomain" value as I was receiving an error, this answer suggested commenting it out so that's what I've done: https://groups.google.com/forum/#!topic/firebase-talk/eUzTjj8mVa4

  • At first I thought the error was due to the .js file containing FacebookCordova not being included between the head tags, but this isn't correct, as
    FacebookCordova
    is defined in
    [projectname]\plugins\cordova-plugin-facebook\www\CordovaFacebook.js
    so it is included in the app.

  • I correctly defined my Facebook App Name and Id when I installed the plugin via node.js.

  • I've included a div with id="fb-root" in the body of my HTML for Facebook functionality.



I'm really confused as to why this error is happening, I just want to integrate a "Log in with Facebook" option and retrieve a key so that I can authenticate the user into Firebase.

Any help or advice with this would be really appreciated, thanks in advance!

Update
This is my current .xml file:

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.myhelloworld" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>HelloWorld</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
</description>
<author email="dev@cordova.apache.org" href="http://cordova.io">
Apache Cordova Team
</author>
<content src="index.html" />
<plugin name="cordova-plugin-whitelist" spec="1" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<preference name="SplashScreen" value="screen" />
<preference name="SplashScreenSpinnerColor" value="#FFFFFF" />
<preference name="SplashScreenBackgroundColor" value="#009900" />
<platform name="android">
<allow-intent href="market:*" />
<splash density="land-hdpi" src="res/screen/android/starsplash.png" />
<splash density="land-ldpi" src="res/screen/android/starsplash.png" />
<splash density="land-mdpi" src="res/screen/android/starsplash.png" />
<splash density="land-xhdpi" src="res/screen/android/starsplash.png" />
<splash density="port-hdpi" src="res/screen/android/starsplash.png" />
<splash density="port-ldpi" src="res/screen/android/starsplash.png" />
<splash density="port-mdpi" src="res/screen/android/starsplash.png" />
<splash density="port-xhdpi" src="res/screen/android/starsplash.png" />
</platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
</platform>
<engine name="ios" spec="~4.2.1" />
<engine name="android" spec="~5.2.2" />
<plugin name="cordova-plugin-facebook" >
<variable name="APP_ID" value="MYAPPID" />
<variable name="APP_NAME" value="MYAPPNAME" />
</plugin>
</widget>

Answer

I don't see that your code includes cordova.js. Your HTML file should have the following line:

<script type="text/javascript" src="cordova.js"></script>

Without that, the Cordova web/native bridge can't initialize, and the plugins won't work either.