WorryFree Computers   »   [go: up one dir, main page]

Sara Robinson
Sara Robinson
Developer Advocate

Cy is the Founder of Crowdsound, a realtime audience engagement tool built with Firebase and Angular.

What is Crowdsound?

Crowdsound is a one-stop shop for live events.



Whether you’re creating a talk, a panel, a seminar, a news show, or any live event, you can interact with your audience in real time. Crowdsound allows you to look at your audience’s demographics, take questions from audience members, quickly poll them, and follow up with them later.

On top of that, Crowdsound gives those audience members a say in the conversation. They become more than just users: they become participants. They can even message each other to stay in touch after the event is over. No more fumbling to to exchange contact info.

What inspired you to build the app?

It began with trying to get feedback on a talk of ours. While we were trying to solve this problem, we realized that there was a bigger issue at hand. How could we get active participation from an audience? The problem became clearer when the event got broadcasted live to a virtual audience.

Right now, most events are like one-way streets: you simply deliver content to passive viewers and listeners. We were inspired by the idea of finally giving audience members active voices in the conversation, regardless of where they’re located.

The first time I witnessed a speaker answer my question during a livestream was exhilarating. I felt included in the event and immediately invited more of my friends. We want more people to feel exhilarated--to feel like they’re being heard. We want to enable large groups of people to share their ideas and collaborate to reach their goals. That’s what motivates us at Crowdsound.

How are you using Firebase and Angular?

Because of the real-time nature of our app, we built it completely on Firebase and Angular. We are truly putting Firebase’s capabilities to the test.

It was clear we needed a tool to send live data changes to thousands of devices simultaneously. Without Firebase, we would’ve needed a much bigger team, and that team would’ve taken months to build what we’ve built in just a couple of weeks.

In addition to AngularFire we’re using a custom implementation of Kato Richardson’s synchronized array.

What other technologies are you using?

We have a Node server on Heroku and static assets on Amazon S3. The great thing about Firebase (and its Security and Firebase Rules) is that it gives us a centralized place to exchange data. That way, we can use Firebase as an API to our own servers and make more complex queries. It’s especially useful when we need to crunch analytics information for our customers.

What are some of the most interesting use cases of crowdsound you've seen so far?

Professors using Crowdsound to quiz their students in real time. It's great to see them quickly getting a pulse on how well their students are absorbing the material.

In a classroom setting, we’re deterred from speaking up when we don't understand a concept because we don’t want our peers to think we’re not as smart as they are. It’s human nature. Unfortunately, what often happens is that half the class doesn’t understand something, but no one actually wants to speak up. Crowdsound lets teachers test their students anonymously on the fly and use the results to focus on the concepts that actually need extra attention.

What's next on your roadmap? Any exciting upcoming features you can share?

We’re excited to share that native video streaming and private rooms are coming very soon. After witnessing our customers fidgeting with Google Hangouts that only allow 10 users and other streaming services that take forever to set up, we wanted to create a one-stop solution with everything you need to run your live event out of the box.

Chris Raynor
Chris Raynor
Core Developer

Today we’re excited to launch Firebase Hosting, production-grade hosting for developers. Firebase Hosting is designed for use by mission-critical sites and apps. We’ve built it from the ground up for security, reliability, and scale.

Key features of Firebase Hosting include:


  • CDN-backed global content delivery

  • Automatic SSL certificate provisioning

  • Support for non-SNI devices, to ensure all users have a secure experience

  • Custom (and even naked) domain support

No other hosting service matches these features.

On top of this, we’ve made Hosting incredibly simple to use by providing one-command deploy and one-click rollback. Developers now have a fast, secure, and reliable way to host their apps.

The Rise of the Static App

Once upon a time, in the dark ages of the internet, apps dynamically generated HTML server-side every time a page was requested. This was slow, difficult to scale, and required users to connect to distant servers to get their content.

Even worse, this required clients to talk to a server on every state transition. For mobile users, this meant applications would break the moment connectivity was lost.

With the advent of fast JavaScript engines and powerful mobile devices, client-side page generation has become common. Angular, Ember, React, and a number of other client-side rendering technologies have transformed the application stack. Servers no longer need to send different HTML to each client. Instead, a single optimized set of static assets can be served to all clients. These static assets can then be placed on a geographically-distributed CDN, meaning users need only load data from a nearby point-of-presence (POP) rather than a server on the other side of the planet.

This new model has advantages for both end users and developers:

  • Faster Load Times: Static assets are cacheable and can be served from a local CDN POP.

  • Smoother State Transitions: Apps no longer need to load HTML from servers to move from page to page.

  • Apps Work Offline: Application logic runs on the device, meaning apps remain responsive even without network connectivity.

  • Easier to Scale: Delivering static content is easier than scaling server processes.

  • Less Complex Operations: Fewer servers to worry about means you can spend more time writing code.

  • Better Cross-Platform Support: Since all dynamic data is loaded from an API, it’s easier to build for mobile, web, IoT, etc.

The Role of Firebase

Static apps load dynamic, personalized data from an API. Firebase is a popular choice for this API since we eliminate the need for server-side code and allow apps to deliver data changes in realtime. We’ve been thrilled to be a part of this shift and are especially excited about the popularity of our bindings for Angular, Ember, Backbone, and React.

However, providing only an API for dynamic data left our developers needing to find their own solution for hosting their assets: HTML, JavaScript, images, etc.

You Asked. We Built Something Awesome.

You, our developer community, voiced your frustration with existing hosting solutions. None of them had the same level of ease, reliability, and polish as the Firebase API. Since hosting is such an integral part of app development, we chose to solve the problem ourselves.

What does this mean for you?

It means we've thought hard about how hosting should work. Firebase Hosting includes:

1. One-command deploys; one-click rollbacks

Deploy your content in seconds with the Firebase command line interface. Once uploaded, content begins serving immediately. With one click in the App Dashboard you can rollback to an earlier version and it will begin serving immediately. There’s no need to re-upload an old version if you’ve made a mistake, saving you precious time.

2. SSL by default

Every app on Firebase Hosting is served over HTTPS. Gone is the pain and expense of buying and installing an SSL certificate. From acquiring the cert to securing your domain, we do it all for you.

3. Your own domain

If you have a paid account, you can serve content from any custom domain, even a naked domain. Using our free plan? Don’t worry, you’ll get all the other advantages of Firebase Hosting on your own firebaseapp.com subdomain, for free!

4. Lightning fast content delivery

With Firebase Hosting you get a global footprint out of the box. We’re using one of the fastest CDNs available. Content is cached at POPs in North America, Europe, and Asia Pacific on SSDs, meaning no matter where your users are, they get your content fast.

5. Straight-forward pricing

We’re rolling Firebase Hosting into our existing plans, without raising the price! If you’re on our free Hacker plan you get:


  • Free hosting at <your-app>.firebaseapp.com

  • 1 GB of storage

  • 100 GB of transfer


If you’re on our Candle, Bonfire, Blaze or Inferno plans you get:


  • Hosting on your custom domain and an SSL cert at no additional charge

  • 10 GB of storage ($0.03 / GB above that)

  • 1 TB of transfer ($0.10 / GB above that)

Get started!

Firebase Hosting is available starting today. Over 1,000 apps and sites have been deployed in our beta period and we're using it to host Firebase.com!

Get started by signing up. For more details, check out the documentation.

Welcome to the future of hosting!

Chris Raynor
Firebase Hosting Lead

Michael Wulf
Kato Richardson
Support Hacker

In our last blog post, we discussed best practices for using arrays in Firebase. If you haven't read that, please start there. This blog post will discuss advanced concepts for converting between real-time objects and sortable, filterable arrays.

Okay, so let's get some working gloves on and start handling synchronized arrays. If we want client-side sorting, filtering, and other things arrays are great at, but also need the awesome collaborative aspects of real-time objects, then we're going to be up to our elbows in code. We're going to work in JavaScript here, because that's what I'm most familiar with. All of these techniques can be translated to iOS and Android as well.

Using Existing Libraries

Before we get started, it's worth mentioning that there are some great frameworks that have already resolved the problems we face with synchronized arrays. In fact, we'll be drawing from the principles of their array management throughout this article.

EmberFire provides array handling out of the box, integrating Firebase neatly into the Ember.js framework. If you're already a glowing Ember dev, check out the Ember + Firebase Guide for details.

AngularFire version 0.8.0 provides utilities for using arrays in Angular. If you are an ngDev, Check out the Angular + Firebase Guide for details.

BackboneFire provides similar capabilities for those osteologists who prefer Backbone's flexible MVVM.

Best Practices for Synchronized Arrays

Drawing from the lessons learned in developing libraries like AngularFire, we can lay down a solid set of principles to keep ourselves out of trouble:

  • Make the synchronized array read only (use setter methods instead of splice/pop/etc)
  • Add a unique id (the Firebase key) to each record
  • Server changes get written directly into our array
  • Local changes are pushed to the server, then trickle back

In other words, our array is essentially a one-directional loop. Changes come from the server into the array, we read them out, we push our local edits to the server, they trickle back into the array.

Okay, let's get started handling synchronized arrays in Firebase.

Pulling Data from Firebase

Let's start simple:

function getSynchronizedArray(firebaseRef) {
  var list = [];
  // put some magic here
  return list;
}

This provides a method we can pass a firebaseRef into and get back an array. Now let's put some data into it.

function getSynchronizedArray(firebaseRef) {
  var list = [];
  syncChanges(list, firebaseRef);
  return list;
}

function syncChanges(list, ref) {
  ref.on('child_added', function _add(snap, prevChild) {
    var data = snap.val();
    data.$id = snap.key(); // assumes data is always an object
    var pos = positionAfter(list, prevChild);
    list.splice(pos, 0, data);
  });
}

// similar to indexOf, but uses id to find element
function positionFor(list, key) {
  for(var i = 0, len = list.length; i < len; i++) {
    if( list[i].$id === key ) {
      return i;
    }
  }
  return -1;
}

// using the Firebase API's prevChild behavior, we
// place each element in the list after it's prev
// sibling or, if prevChild is null, at the beginning
function positionAfter(list, prevChild) {
  if( prevChild === null ) {
    return 0;
  }
  else {
    var i = positionFor(list, prevChild);
    if( i === -1 ) {
      return list.length;
    }
    else {
      return i+1;
    }
  }
}

Okay, now our array is getting populated from Firebase. Next, let's deal with the other CRUD operations, and move events.

function syncChanges(list, ref) {
  ref.on('child_added', ...); // example above

  ref.on('child_removed', function _remove(snap) {
    var i = positionFor(list, snap.key());
    if( i > -1 ) {
      list.splice(i, 1);
    }
  });

  ref.on('child_changed', function _change(snap) {
    var i = positionFor(list, snap.key());
    if( i > -1 ) {
      list[i] = snap.val();
      list[i].$id = snap.key(); // assumes data is always an object
    }
  });

  ref.on('child_moved', function _move(snap, prevChild) {
    var curPos = positionFor(list, snap.key());
    if( curPos > -1 ) {
      var data = list.splice(curPos, 1)[0];
      var newPos = positionAfter(list, prevChild);
      list.splice(newPos, 0, data);
    }
  });
}

Great, now our array is completely synchronized with the remote data. Now we just need some local editing capabilities.

Pushing Local Updates

We won't modify our array directly. We can do ops like sort to re-order the data, but if we start trying to
do ops like splice or pop, and have the server modifying this array as well, things will get ugly.

Instead, we'll directly push changes to the server with some quick wrapper methods. Since Firebase triggers events
for local changes immediately, without waiting for a server response, this is quite performant and simplifies the
process as well:

function getSynchronizedArray(firebaseRef) {
  var list = [];
  syncChanges(list, firebaseRef);
  wrapLocalCrudOps(list, firebaseRef);
  return list;
}

function syncChanges() { /* in examples above */ }

function wrapLocalCrudOps(list, firebaseRef) {
   // we can hack directly on the array to provide some convenience methods
   list.$add = function(data) {
      return firebaseRef.push(data);
   };

   list.$remove = function(key) {
     firebaseRef.child(key).remove();
   };

   list.$set = function(key, newData) {
     // make sure we don't accidentally push our $id prop
     if( newData.hasOwnProperty('$id') ) { delete newData.$id; }
     firebaseRef.child(key).set(newData);
   };

   list.$indexOf = function(key) {
     return positionFor(list, key); // positionFor in examples above
   }
}

And there we are! We can now manipulate our array by using operations like this:

var ref = new Firebase(URL);
var list = getSynchronizedArray(ref);

// add a record
var newRecordId = list.$add({ foo: 'bar' }).key();

// remove a record
list.$remove(recordKey);

// update a record
var data = list[5];
data.foo = 'baz';
list.$set( data.$id, data );

A Working Example

That's pretty much it! There are a few additional edge cases that we can cover, but we've created a
synchronized array that merges local changes with server updates and keeps all of it in a tidy array.

Here's an example project utilizing these principles you can use
as a template for baking your own solutions. Check out the README for installation instructions.

More To Come!

At Firebase, we're never satisfied with just being awesome. We are constantly working to improve all these scenarios and have several API enhancements in the pipeline. Keep an eye on the Google Group for details and announcements.

Find this article useful or have additional questions? Leave a comment below or post a message on the Google Group!

Jacob Wenger
Jacob Wenger
Core Developer

ReactJS is a JavaScript library built by Facebook and Instagram which makes it easy to build large, complex user interfaces. It is intended to be used in combination with another framework which provides the backend. While Angular, Ember, and Backbone are popular choices for that, Firebase provides the easiest and quickest integration of a persistent, realtime backend into a React app - and it takes only a few lines of JavaScript.

Note: This post requires a basic knowledge of React. You can get up to speed quickly by looking through the short tutorial on the React homepage.

What is React?

The creators of React describe it as the "V[iew] in MVC." It is not meant to be a replacement for Angular or Ember; instead, it is meant to extend their functionality by providing a high-performance way to keep a view up-to-date with JavaScript. Its special sauce is that it renders HTML using an incredibly fast virtual DOM diff algorithm, providing much better performance than competing platforms. It has a "one-way reactive data flow" which is much simpler to understand than traditional data-binding. Components - the basic building blocks of React apps - are organized in a tree hierarchy in which parent components send data down to their children through the props variable. Each component also has a state variable which determines the current data for its view. Whenever state is changed, the component's render() method is called and React figures out the most efficient way to update the DOM.

Since React's main focus is on the user interface, apps made with it need something else to act as their backend. That is where Firebase comes in. It adds the "M[odel] and C[ontroller] in MVC" to React apps, making them fully functioning apps. Using React's straightforward binding system, it is easy to integrate Firebase in a native way with only a small amount of code.

Adding Firebase to a React app

Let's look at the Todo app on the React homepage. Within the TodoApp component, this.state is used to keep track of the input text and the list of Todo items. While React ensures that the DOM stays in sync with any changes to this.state, the changes do not persist beyond the life of the page. If you add a few items and then refresh the page, all of the items disappear! This is because React has no mechanism for storing data beyond the scope of the current page session. It relies on being used with another framework to do that.

Firebase is a natural complement to React as it provides React apps with a persistent, realtime backend. The first thing we need to do is add Firebase to the project:

<head>
  <!-- React JS -->
  <script src="http://fb.me/react-0.10.0.min.js"></script>
  <script src="http://fb.me/JSXTransformer-0.10.0.js"></script>

  <!-- Firebase JS -->
  <script src="https://cdn.firebase.com/js/client/1.0.17/firebase.js"></script>
</head>

Now that we have included Firebase, we can populate the list of Todo items by reading them from Firebase. We do this by hooking into the componentWillMount() method of the TodoApp component which is run once, immediately before the initial rendering of the component:

componentWillMount: function() {
  this.firebaseRef = new Firebase("https://ReactFireTodoApp.firebaseio.com/items/");
  this.firebaseRef.on("child_added", function(dataSnapshot) {
    this.items.push(dataSnapshot.val());
    this.setState({
      items: this.items
    });
  }.bind(this));
}

This code first gets a reference to the items node at the root of the Firebase. The call to on() will be run every time a node is added under the items node. It is important to realize that a child_added event will be fired for every item under the items node in Firebase, not just new ones that are added to it. Therefore, when the page is loaded, every existing child under the items node will fire a child_added event, meaning they can easily be iterated over and added to this.state.items. Note that the call at the end to bind() just sets the scope of callback function to this.

Now what about adding new Todo items to the Firebase? That code is just as easy:

handleSubmit: function(e) {
  e.preventDefault();
  this.firebaseRef.push({
    text: this.state.text
  });
  this.setState({text: ""});
}

Within handleSubmit() a new item is pushed onto the saved Firebase reference which appends it to the end of the items node. The call to setState() updates this.state.text but does not need to update this.state.items as it did in the original React code. This is because the child_added event handler from componentWillMount() will be fired when a new child is pushed onto the items Firebase node and that code will update this.state.items.

The last thing that needs to happen is cleaning up the Firebase event handler:

componentWillUnmount: function() {
  this.firebaseRef.off();
}

With just the few changes above, items added to the Todo list are updated in realtime. Best of all, the items stick around if the page is refreshed! You can even open multiple tabs pointed at the same page and see them all update simultaneously, with Firebase doing all the heavy lifting. Take some time to view the code for this example and play around with a live demo (Note: it's the second one on the demo page).

Introducing the ReactFireMixin

Although integrating Firebase into a React app only takes a few lines of code out of the box, we wanted to make it even easier. That is why we built the ReactFireMixin for React which makes it simple to keep this.state in sync with a Firebase node.

We suggest you download ReactFire directly from our CDN:

<!-- ReactFire -->
<script src="https://cdn.firebase.com/libs/reactfire/0.1.6/reactfire.min.js"></script>

ReactFire is also available from npm via npm install reactfire or from Bower via bower install reactfire.

To then use the ReactFireMixin in the TodoApp component, add it to the component's mixins property:

var TodoApp = React.createClass({
  mixins: [ReactFireMixin],
  ...
});

The ReactFireMixin extends the functionality of the TodoApp component, adding additional Firebase-specific methods to it. To keep this.state.items in sync with any changes to the items node in the Firebase, make the following change in componentWillMount():

componentWillMount: function() {
  this.bindAsArray(new Firebase("https://ReactFireTodoApp.firebaseio.com/items/"), "items");
}

We simply specify that we want to bind a particular Firebase reference to this.state.items of the React component. The ReactFireMixin allows binding to a Firebase node as an array or as a regular JavaScript object. This creates a one-way binding from the Firebase reference to this.state.items, meaning that if the data in the Firebase changes, so will this.state.items. However, if we update this.state.items, the Firebase will not change. Therefore, changes should be made directly to the Firebase and not by calling setState():

handleSubmit: function(e) {
  e.preventDefault();
  this.firebaseRefs["items"].push({
    text: this.state.text
  });
  this.setState({text: ""});
}

The ReactFireMixin allows for binding to multiple things at once. Firebase ensures that this is all done in an efficient manner. To access the Firebase reference which is bound to this.state.items, we can reference this.firebaseRefs["items"] which is provided by the ReactFireMixin. Finally, calling this.firebaseRef.off() is no longer needed in componentWillUnmount() as the mixin handles this behind the scenes.

You can view the code for this example and play around with a live demo (Note: it's the last one on the demo page).

Conclusion

ReactJS is a wonderful framework for creating user interfaces. When picking a complementary tool to use alongside it as a backend, Firebase is the easiest and most powerful solution. In just a few lines of code you can get a React app syncing data across hundreds of clients at once. Our new ReactFireMixin makes this that much easier, getting rid of even more boilerplate code.

We encourage you to try out the new ReactFireMixin for React and let us know what you think. If you have any questions or feedback, post them in our Firebase Google Group or email me at jacob@firebase.com. Submit a pull request to our examples repo if you have any Firebase + React examples you would like to share.

We are excited to see what you create!