2.12 Working With Internal Links
There's a better way to do page-to-page links: we can define a custom syntax with
]] brackets. Let's do so in this lesson.
1.Getting Started6 lessons, 27:04
2.Building the Application13 lessons, 1:29:43
3.Conclusion1 lesson, 00:44
2.12 Working With Internal Links
In the previous lesson, we tweaked our section code so that users could successfully navigate to links from within a section, without unintentionally editing the section. And we set it up so that if they made links to other pages within the Wiki, we wouldn't have to reload the page. However, there's an even easier syntax that we could use for internal links. Instead of them having to know the ID for the individual page, what if we just allowed them to use double square brackets for links? Right now, if we do that, you can see we just see the double square brackets there. And it's just regular HTML. We have the word Dogs there within double square brackets. In this lesson, what we're going to do is write a function that will convert that syntax right there into internal links for us. Here in our section.js file, right at the bottom of our section class, let's add a new function. And this going to the makeLinks. Now makeLinks is going to take two parameters. First is going to be the HTML. This will be the HTML that we get after rendering our markdown. As we just saw in our application, after we render the HTML, we still have the double square brackets. So will be able to take that HTML and swap those square brackets out for a link. The second parameter that we have to makeLinks is a callback function. This is because we're going to need to make an API request to get a list of all the pages in our database. Of course, this means that because of the asynchronous nature of accessing our data in Firebase, we can't actually return something from the makeLinks function, so we'll have to give it to a callback and then call that call back. Okay, let's start by creating a regular expression here. Will create a constant and that will be called anchor. And this is going to be a regular expression that matches our internal link syntax. So it will matched two opening square brackets and then it will capture whenever text is in between them and then it will match two closing square brackets. The next step is to make our API call to get our list of pages. So we can do API.pages.once to get the value of pages one time. And then when we get that snapshot back, we'll convert that snapshot to an object. We'll just call back pages. And we can do that by calling snapshot.ExportVal. Then we'll get the IDs for those pages by saying Object.keys for pages, and we'll store those in the keys variable. And at this point, we have everything we need to do the actual replacement. So we'll do HTML, which is our HTML string. And we'll say HTML.replace. And we will replace wherever we find something that matches our anchor regular expression. And then instead of just replacing that with a hardcoded string, we're going to pass in a function. And this function will get a match object as the first parameter. And as a second parameter it will get our first capture group. So we'll call that our anchorText. Now inside this function, we have to loop over all of our pages and find the one with the title that matches our anchorText. So we'll start by looping over our key's array by using a for loop and we can just say let key of keys. And then for each key we'll run an if statement. We'll say if pages[key].title. So the title of the current page that we're looping over is equal to anchorText and we'll say .trim just to make sure we are not gonna miss something because of whitespace. So if the title of the page that we're looking at does match the anchorText, then we will return a string. And I'm using ES6's template strings here. These are delimited by back ticks. And we can interpolate values inside of them by using dollar sign, curly brace as the opening delimiter and closing curly brace as the closing delimiter. So we'll just set this to be an anchor with an href of /page/ and then key, which is, of course, the ID for that page. And then inside the anchor element, we'll just put the anchorText itself. And really it's that simple. This way, every one of our internal links that we have with the double square brackets syntax inside of our HTML will be replaced with an actual anchor tag. So our call to html.replace will return our new HTML. So we'll just wrap that in our callback function and now makeLinks is finished. So we're going to use makeLinks up in our componentWillReceiveProps function. We can call this this .makeLinks and we'll pass it state.html. Remember we got that state object by calling our getState function. And then when that HTML is returned, we can replace state.html with our new HTML. And finally, we'll set the state by calling this.setState with our new state object. If you think about it for a second, you might realize why this isn't exactly what we need. Let's go back to our browser here and give this a try. If we refreshed the Cats page, you can see that right now we don't actually have our link displaying. We still see the square brackets. However, if we navigate to the Dogs page and then back to Cats, now you can see we do see the link. The reason we're seeing this behavior is because we called our makeLinks function from within componentWillReceiveProps. Right? And that doesn't happen the first time the component is rendered. Instead, it happens whenever the component is receiving new properties. And that doesn't happen when we refresh the page. The call that will happen when we refresh the page is componentDidMount. So let's add a componentDidMount function to our section class. From in here, we can just call this.componentWillReceiveProps and pass in the current properties. If we go back to the browser and refresh the page, you can see that immediately upon refresh, we have our link displaying, which means that our internal link functionality is complete.