Coder Social home page Coder Social logo

ember-objects-al's Introduction

Ember Objects

While you may never have to write your own Ember Object, you should know how they work since everything you'll be working with inherits from it.

Ember Models Models Inherit from Ember.Object Ember Controllers Controllers Inherit from Ember.Object Ember Services Services Inherit from Ember.Object

Because of this, knowing how to work with Ember Objects is kind of a big deal. Let's get started.

Creating Instances

Creating a new instance of a generic Ember Object is easy.

var obj = Ember.Object.create({name: "Bob"});
obj.get("name"); // "Bob"
obj.get("age"); // undefined
obj.set("age", 35);
obj.get("age"); // 35

Ember Objects expect you to interact with properties using the get and set methods. These methods allow Ember to update dependent properties, as we'll see later in the Computed Properties section.

Ember Objects are like JavaScript objects, in that they are open. You can add any property to an object, no need to define setters.

What if we don't want a generic object? What if we want to design an object with functions and properties? Enter the extend method.

var Person = Ember.Object.extend({
  name: null,
  greet: function(){
    return `${this.get("name")} says "Hi!"`;
  }
});

var bob = Person.create({name: "Bob", age: 35});
bob.greet(); // Bob says "Hi!"

Here we create a Person Object. We can pass create properties, even if they're not defined in the prototype. It's a good idea to set the expected properties to null to let users of your Object know what it expects. It's not required though.

In the tests you will see your classes imported like this:

export default Ember.Object.extend();

This is the same as saying:

var MyObject = Ember.Object.extend();
export default MyObject;

It's a shortcut.

Computed Properties

Computed properties are a super power in Ember and the fact that they're in EVERY OBJECT should get you excited. A computed property is a property that gets updated as your object changes. You define a list of properties you depend on, and when one of those properties changes (meaning someone called set on it), your computed property will also change. It's lazy so it won't regenerate the value every time, only when there's a change.

Instead of defining a function that we will invoke every time we want to grab its return value, we can build a computed property that will only be invoked when one of the properties that it depends on has changed.

Here's a simple example:

Let's say we want to have the total price of an item update based on the price × the quantity. In regular javascript you might define a function called total that will multiply price and quantity. This calculation would run every time it's called. With computed properties that computation is only run when a dependent property (in this case price or quantity) changes.

Here's the Ember code for that:

var Item = Ember.Object.extend({
  price: 0,
  quantity: 0,
  total: Ember.computed("price", "quantity", function(){
    return this.get("price") * this.get("quantity");
  })
})

var ham  = Item.create({price: 3, quantity: 1});
ham.get("total"); // 3
ham.get("total"); // 3
ham.set("quantity", 5)
ham.get("total"); //15

Let's break this down:

  • First, we create an item, ham, that has a price of 3 and a quantity of 1.
  • Then, we get the computed property that we called total. This will be calculated and return 3.
  • Then, we get the computed property, total, again. This time, however, the calculation isn't run. Our Ember object remembers that has a computed property called total, that is currently set to 3.
  • Then, we set the quantity property equal to a different number, 5. Our computed property, total, depends on the quantity property and is listening to any changes that might have occurred to that or its other dependent property. Now that the value of the quantity property has changed, the total computed property will be re-calculated. Which is exactly what happens on the next line.

Be sure to look at computed properties created Ember makes for you here.

Working with collections

Ember lets you monitor changes to the properties in a collection too. Let's setup a shopping cart with items. The shopping cart will hold a series of items.

var ShoppingCart = Ember.Object.extend({
  items: [],
  total: Ember.computed("[email protected]", function(){
    return this.get("items").reduce(function(memo, item){
      return memo + item.get('total');
    }, 0);
  })
});

var Item = Ember.Object.extend({
  price: 0,
  quantity: 0,
  total: Ember.computed("price", "quantity", function(){
    return this.get("price") * this.get("quantity");
  })
});
var ham     = Item.create({price: 3, quantity: 1});
var cheese  = Item.create({price: 5, quantity: 1});
var bread   = Item.create({price: 2, quantity: 1});

var cart = ShoppingCart.create();
cart.get("total"); // 0

cart.get('items').pushObjects([ham, cheese, bread]);
cart.get("total"); // 10

This function will run only when the total property of an item is changed. We used that weird [email protected] property to say just that. The @each is a special key that listens to any changes in the total property of all of the elements in the items collection. It will notify the computed property that contains it when any of the items; totals have changed.

What if we wanted to update when an item is added or removed? Say we wanted a total number of items in the cart:

var ShoppingCart = Ember.Object.extend({
  items: [],
  total: Ember.computed("[email protected]", function(){
    return this.get("items").reduce(function(memo, item){
      return memo + item.get('total');
    }, 0);
  }),
  numberOfItems: Ember.computed("items.[]", function(){
    return this.get('items.length');
  })
});

var Item = Ember.Object.extend({
  price: 0,
  quantity: 0,
  total: Ember.computed("price", "quantity", function(){
    return this.get("price") * this.get("quantity");
  })
});
var ham     = Item.create({price: 3, quantity: 1});
var cheese  = Item.create({price: 5, quantity: 1});
var bread   = Item.create({price: 2, quantity: 1});
var cart = ShoppingCart.create();
cart.get("numberOfItems"); // 0

cart.get('items').pushObjects([ham, cheese, bread]);
cart.get("numberOfItems"); // 3

Here we did 2 things. One is the use of items.[]. This means update the computed property if the number of elements changes. You won't be notified of changes to properties, unlike the @each we used above. The other thing we did is return this.get('items.length'). Ember lets you chain messages inside of gets and setss.

You can use a short hand for this though, by using one of Ember's built in computed properties. Basically what we're doing is creating an alias for items.length that updates. Instead of the function we have for numberOfItems, we can have this instead:

var ShoppingCart = Ember.Object.extend({
  items: [],
  total: Ember.computed("[email protected]", function(){
    return this.get("items").reduce(function(memo, item){
      return memo + item.get('total');
    }, 0);
  }),
  numberOfItems: Ember.computed.alias("items.length")
});

var Item = Ember.Object.extend({
  price: 0,
  quantity: 0,
  total: Ember.computed("price", "quantity", function(){
    return this.get("price") * this.get("quantity");
  })
});
var ham     = Item.create({price: 3, quantity: 1});
var cheese  = Item.create({price: 5, quantity: 1});
var bread   = Item.create({price: 2, quantity: 1});
var cart = ShoppingCart.create();
cart.get("numberOfItems"); // 0

cart.get('items').pushObjects([ham, cheese, bread]);
cart.get("numberOfItems"); // 3

So nice!

View Ember Objects on Learn.co and start learning to code for free.

ember-objects-al's People

Contributors

octosteve avatar sophiedebenedetto avatar ember-tomster avatar

Watchers

James Cloos avatar  avatar Mohawk Greene avatar Victoria Thevenot avatar Bernard Mordan avatar Otha avatar raza jafri avatar  avatar Joe Cardarelli avatar The Learn Team avatar  avatar  avatar Ben Oren avatar Matt avatar Antoin avatar Alex Griffith avatar  avatar Amanda D'Avria avatar  avatar Ahmed avatar Nicole Kroese  avatar Dominique De León avatar  avatar Lisa Jiang avatar Vicki Aubin avatar Maxwell Benton avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.