• Meteor
  • Tutorial

Spark Landmark Annotation

In the last video, we talked about the events and Watch annotations that Spark uses to wire up events. And in this video, we're going to talk about the Spark Landmark annotation. I think the landmark annotation is one of the coolest ones. And if you've ever been curious about when the Rendered callbacks or Created callback gets called or how preservations work, this video will hopefully shed some light on those topics.

So similar to the previous Spark annotation videos, we're going to be looking under the covers at what happens with the Landmark annotation itself. And at some future video, we'll tie that back to Meteor templates, which is what you would normally work with in your projects. But hopefully, this video will give you a sense of what's happening behind the scenes.

OK. To get us started, in the left, I have some boilerplate code that hopefully should be familiar to you by now. Down at the bottom, I have some meteor startup code that either shows the template annotations or renders the template to the body. And by template here, we're talking about not a meteor template, but a custom function that we wrote that's right here.

And right now, all that function does is it returns the result of calling the HTML func. So if we jump up to that function, we can see that at some point we're going to make this reactive. So to start us off, what I do is I grab a title from the session, and then I just return some HTML. This is just a fancy way of using an array to create some HTML elements and then returning a string by calling the Join method on the array. So this will be an H1 element with the title in between, and then the closing H1 tag.

And b over on the right, we can see that our annotated HTML at first is just the HTML itself-- the H1 tag, and then this very crafty string in between. It's a bird. It's a plane. It's a landmark. So what we want to do is we want to start creating the landmark.

So to do that, instead of just returning the result of calling HTML func, what I'll do is I will turn the result of calling spark.createlandmark. And that method takes two parameters. The first is going to be an object that is a bunch of options. And we'll fill that out in a minute. But we'll call it Landmark Options.

And the second parameter is just going to be a callback that's called when the landmark has been created. And so we'll just call that a function named On Landmark. So let's come up here and define these this object and this function now. So the first one will be called Landmark Options. And then we'll define a function called On Landmark.

And that function, when it's called, will get a landmark, the newly created landmark, as a parameter, and then we can do whatever we want with the landmark. But for now, what I'm going to do is just return the result of calling HTML func again. Great. Once our code refreshes in the browser, we can see down in the console that our annotated HTML now includes the landmark annotation around the HTML string in the middle.

Next, let's comment out the show template annotations and instead render the template to the body. And before we dig into adding landmark options, I just want to show you what a landmark object looks like. So I'm going to do a little trick here. I haven't explained live ranges yet. But in order to see the landmark object, we need to dive into the live range that's associated with this H1 tag.

So to do that, I'm going to go over into my Properties and click the H1 tag. And you see at the top here this special Spark property? Don't worry about it quite yet. But we're just going to dig into that, and we're going to see this live range as the first element of this array.

So this time, I'm not going to dig into the source code to look at the materialiazation function for a landmark annotation. But instead, I'm just going to show you the end result in the debugger. So if we look over here at this live range, we can see that what the materialization function for Create Landmark does is it creates this new landmark object which has some methods that you may have seen before from the templates, like Find and Find All and First Node and Has Dom and Last Node. And then it also adds some methods to the live range itself, like this Destroyed method, Finalize method, Preserve, and the Rendered Callback.

OK. Let's start creating some landmark options that will pass into the Create Landmark method. The first set of methods will be our callbacks. So the first one will be the created callback. And what we'll do inside this callback is just print to the console that the landmark has been created. And then let's take a look at what the value of this is and whether any arguments are passed in.

And then we'll create another callback for rendered. It's important that you spell it right. And we'll do the same thing here. We'll just say that the landmark has been rendered. We'll show what this points to and whether any arguments were passed. And finally, we can use a Creative Destroy callback as well.

OK. Over in the browser, we can see that during materialization, the created callback gets called. And the This argument points to the landmark itself, and there's no arguments that are passed to the function. And then once the landmark is in the dom, this rendered callback gets called, and similarly, the This arg points to the landmark object itself.

OK. In our HTML func, we can see that we're using the title in the display of our HTML. And that comes from Session, which is a reactive data source. But if in the browser in the console I type session.settitle and I try and change it, the HTML doesn't update. And that's because we haven't actually created a Spark isolate annotation. So let's do that now so that we can play with preservations.

So inside our On Landmark callback, what we'll do is instead of just returning the result of calling HTML func, we'll return the result of calling spark.isolate. And as a parameter, we'll pass the HTML func method. So now we have both an Isolate annotation and the Landmark annotation.

And so this time, in the console, if I type session.settitle, we should expect the HTML to re-render. And you can see that the HTML re-renders, and then our rendered callback is called again in the JavaScript console.

Now, sometimes, during that re-rendering process, you want certain HTML nodes not to be touched by Spark. For example, if you have a text input or a video or something that you don't want to be affected by the re-render, Meteor provides a way for you to preserve or leave that node untouched during re-rendering.

So the way that we do that if we create another option in Landmark Options called Preserve. And Preserve can take an array of selectors. And so in this case, we'll just say we want to preserve the H1 element.

And after we've added the Preserve option, over in the browser, I've set two breakpoints to slow down the re-rendering process so that we can actually see what's happening. And I will type session.set, and we'll change the title to 2 and jump into the debugger.

So I'm going to press play once, and then again. And so it looks like the HTML has been removed from the dom, but it turns out that it's just the text that has been removed, because the text was the part that changed the actual title. But if I look in Elements and I just refresh it, what I can see is the H1 tag is actually still there. It just doesn't have anything in it. So what Spark did was it preserved these H1 tags and only changed the title in the middle. Pretty cool, huh?

So let's continue the rendering process. I'll press Play again in the debugger. It looks like I need to go over to Sources, and I'll press Play again. And now we see the new text rendered to the dom. And if we switch over to Elements, we can see it in the dom here as well.

This was a bit of a contrived example. I can't think of a good reason why you would want to preserve your H1 tags. But I'm hoping that by going through it slowly, you get a better sense of what it means to preserve a node. And in case it wasn't clear, this H1 tag or this H1 node is left exactly intact. And so the old node is equal to the new node.

And what changes is the text node in between. And we get all of that simply by passing in this Preserve option to our Landmark function. Now, of course, this usually happens for you. Because when you're using Meteor templates, you use the Meteor Template Preserve method. And we'll talk about the higher level abstractions in future videos.

But I'm hoping that this gave you a decent sense of what landmarks are and how Meteor templates use them under the hood.