• Meteor
  • Tutorial

Reactive Properties

Let's say that we have an empty object in our application like this. I'm just going to call it myDocument. One of the cool things we can do with modern browsers in JavaScript is to define configurable properties on the document or on the object. I can do that by calling Object.defineProperty and then passing in the object that we want to define the property on, and then the name, and then a set of configuration options.

Some the configuration options include things like an initial value or default value, and then whether or not the value is writeable, whether it's innumerable, and we can even set a getter and a setter function. So for the rest of this video, I'd like to focus on this getter and setter function.

To show you how this works, let's just start off by returning some standard value, like my value. And then when we pass in a new value, I'll just print to the console that we're setting the new value.

OK. Let's take a look in the browser console at myDocument now. Now, notice we have a new property on here called title. And it has this special syntax in the debugger showing us that it has a getter and a setter. So we have this get and a set. So if I, in the console, say myDocument.title, the get function gets called, and the return value is this my value string. And notice, we're not calling a function here. We're just accessing the property, like we do with normal properties.

Next up, let me try setting this property. So I can type myDocument.title equals. Now notice, we're not calling a function set here. We're just assigning to this property a new value. And I'll just say new value here. And we print to the console that we're setting the new value along with what was passed in. And that's because inside of our setter function we pass in the new value and then print out this string to the console.

So one of the cool things we can do with this knowledge of configuring properties is to create reactive properties. We're going to write a function that allows us to create a reactive property that works hand in hand with Deps.

The goal of this design is I'd like to be able to create a computation by calling Deps.autorun. And inside of the autorun function or the computation function, I'd like to be able to get the value of the title. So I'll say the title is a variable title, and that'll be equal to myDocument title. And then we'll just print out the title is of whatever value. And I want this function to re-run any time the value changes.

So what I'm going to do is to define a new property or a new function off of object. And we'll call it define reactive property. And it will take a target object, the name of the property, and maybe an initial value. Then I'll expand this that we can get a better view.

Now inside of this function, what we'll do is just copy and paste what we had written before. And let me change myDocument here to the target that's passed in. And instead of hard coding the title, we'll just pass the name of the property.

And let's create a more sophisticated getter and setter. So I'm going to create a variable here called current value, and that'll be equal to the default value to start. And in our getter function, we'll return that current value, and we'll fill out the setter function in a second. And so then down here, what I'm going to do is call this function. And we'll define a reactive property on myDocument called title with an initial value of initial value.

OK. Over in the browser what I should be able to do now is-- let me save the document first. And then over in the browser, we'll type myDocument.title. And you can see that it says initial value. And it's also printed to the console here in our initial Deps.autorun.

Now let's fill out the set function. And so what I'm going to do in here is to say if the new value is different from the current value, we'll set the current value equal to the new value.

Now, we want to make this work with Deps. And so up here, I'm going to create another variable called our dep, and we'll create a new Deps.Dependency. And in our getter function what we'll do is create a dependency by calling the depend method. And in our set function, once we set the new value, we'll call the changed method to invalidate any computations that use this value.

Now, we're able to create these variables up here that are privately scoped, because we're using this function. And so the variables are scoped to this function. And there are always available inside of our getter and setter functions. But every time we call this define reactive property function, we'll create a new copy of these variables.

So to try this out over in the browser, I'll change the title by assigning it to a different value. And we assign the new value. And then notice that the autorun block runs again. And so our computation gets re-run, and we print out the new title to the console.

And to make this a little bit more clear, let's put this in a set interval so the title gets changed every couple of seconds. So I'll type setInterval. And we'll say every two seconds, set the title to something new. So we'll say myDocument title is equal to-- and I'll use the random ID function, so that we set the title to something random.

Now, keep your eyes over on the console, and you'll notice every two seconds the title gets set to a new random value, and our computations function is re-run. And that's because the title attribute, or the title property, is reactive.

Next up, since this looks like it could be the beginnings of a package, or that I could reuse this functionality in some of my other applications, I'd like to be able to take it and put it into a package. And whenever I'm playing around with creating new packages, I will just put it into the local packages folder of my app. And that way I can try it out within the application.

So down in the console in the bottom, I'm going to create a new package. So I'll change into the packages folder. And I'm going to use the M command line scaffolding tool to help me with this. But you can just create these files and folders manually, if you'd like.

I'm going to generate a new package. And the name of it is going to be Reactive Properties. And then if I open up this folder here, you can see I've got a new package called Reactive Properties. And I'll jump in into package.js and fill this out a bit.

So I'll give it a summary. And it's important in the new packaging system to give this a version. And I'll jump down into the on use block, and we're going to say that this package relies on the Deps package, the Deps core package. Then we'll add Reactive Properties. And we're only going to add them to the client environment.

OK. Next up, I'm going to go back to the root of my project and add this packet. So we'll add Reactive Properties. And now that will add the package to the list of packages that I'm using for this project. So I can say Meteor list using. And you can see, the Reactive Properties package shows up in the list.

Now, I'll take all of this code here, and we'll cut it and put it over here. So now, this package will add this function called define reactive property to the object constructor function, and will allow us to add reactive properties to any object.

Let's make sure this still works in the console. Now, you might need to refresh or restart your Meteor server to get it to pick up the new package. But once we're back in the browser, you can see that the reactive title property has been created on our document, and our Deps computation seems to be working as expected.

So in this video we looked at how to create a reactive property by using the Object.defineProperty function to configure it on an object. And then we looked at how to turn that into a nice little package that might give you an idea for a package you can build yourself and release to Atmosphere.