Simple Angular Blog Engine :: Part 1
I know. I know. There are so many blog engines out there. I just can’t help myself. Even if you are not creating a blog — you might be interested in using a Markdown Editor in your Angular applications.
- Part I: Angular Module with Markdown Editor Component
- Part 2: Creating Blog Post
- Part 3: Display Blog Posts
- Part 4: Refactor to Shared Angular Library
And still, I want to create yet another one. I already have the back end of the application generated/complete using my code generator/scaffolding tool. This tool creates the Web API, services, business layer with business rules, repository for data access, and Entity Framework data access components. So, really my main effort will be the Angular front end — still a lot of work.
The real motivation is to create an Angular client for the blog using a shared Angular library. I also want to be able to reuse the markdown content as source for some guides and ebooks.
Here are some of my top requirements:
- Work with the latest version of Angular.
- Be available from npm.
- The editor and source of the blog must support markdown. I want to leverage the markdown files for my bookdown projects. See: https://bookdown.org/yihui/bookdown/
- The content of the blog posts will be stored as bytes with an indicator as to the source type (i.e., markdown, HTML, or text).
- The application will parse (process) the markdown and create
HTML
output for the blog display. - Work with the Web API
Content
microservice; and other microservices to support the blog engine. - The blog will be an Angular Module library with: Administrative Features (Services and Components), Domain Service, Components, and Directives
The Markdown Editor
After some initial research I selected https://www.npmjs.com/package/simplemde. It has a nice set of features and configurable options. Later, I’ll refactor the implementation to a custom Angular @NgModule as a shared Angular Library — it will allow consumers of the module to provide the configuration to the markdown editor component using the conventional forRoot(..)
static method of the module. The simplemde
npm package already has several options defined as interfaces
. Therefore, it will be easy to set the editor options at runtime.
Let’s get started.
Package Installation
Retrieve the simplemde
package from npm.
npm install simplemde -S
You will also need the types later,
npm install -S @types/simplemde@1.11.6
Styles and Script Configuration
Add the following to the angular-cli.json
file in the styles
section of the apps
node.
"../node_modules/simplemde/dist/simplemde.min.css"
Add the following to the angular-cli.json
file in the scripts
section of the apps
node.
"../node_modules/simplemde/dist/simplemde.min.js"
Create an Application Module
Create a module for the editor.
ng generate module modules\markdownEditor
Add a new component to the editor.
ng generate component modules\markdownEditor\editor
Update the MarkdownEditorModule
to export the component.
Editor Configuration
The editor has a nice set of Options
defined for the configuration. Our implementation is using an Angular module. This will allow us to setup a forRoot
static method to pass along the configuration using the defined interface already provided by simplemde
.
Update Module for Configuration
First thing to do is to create a class that will contain the options using the interface
provided by the editor. We will use this class to pass in the configuration when the module is initialized by the application.
Notice that we need to import the SimpleMDE
class so that we can reference the Options
interface for implementation. Notice that all of the members of the interface are nullable
. Additionally, they are all strongly typed - this is a good thing, right?
To allow the module to accept the configuration when it is initialized, we will create a static
method using the Angular
convention: forRoot(..)
. Import the MarkdownEditorOptions
options and implement the forRoot
static method. This will provide or make available the configuration to the module members at runtime. What we want is the component to be able to use the configuration to initialize an editor instance with the configuration.
Reference the MarkdownEditorModule
The application where I’m using this module uses a Core
module to contain references to modules used by my Angular application. Reference the required items in your CoreModule
or AppModule
whichever makes sense for your application.
import { MarkdownEditorModule } from './../markdown-editor/markdown-editor.module';
import { MarkdownEditorOptions } from './../markdown-editor/markdownEditorOptions';
Update the @NgModule imports
to call the forRoot
method on the MarkdownEditorModule
- this allows us to pass in the configuration for the module.
MarkdownEditorModule.forRoot(editorConfig)
We’ll need to create a editorConfig
instance so that we can pass it in. I'm pretty sure that just initializing a newMarkdownEditorOptions
will not work. We'll probably need to create the instance using the same shape as the MarkdownEditorOptions
class. If all goes well, when we use the editor the default content/value will be Hello Editor...write something amazing.
.
const editorConfig = new MarkdownEditorOptions();
editorConfig.autoDownloadFontAwesome = true;
editorConfig.initialValue = 'Hello Editor...write something amazing.';
Here is the code for the @NgModule that will import and provide the configuration to the MarkdownEditorModule.
Editor Component
It is really amazing that the HTML <textarea>
element with a lot of JavaScript creates the markdown editor.
Here is the code for the EditorComponent
. The constructor is looking for a MarkdownEditorOptions
parameter. Since, this is injected using the the forRoot
of the module during module loading - Angular will use dependency injection and provide the configuration setup in the CoreModule
. The object is verified in the initializeEditor()
method.
The parent
component uses the @Input markdown
to provide the child
editor component the actual markdown content to display. This allows the editor component to be reused because its only responsibility is to display the content. The @Ouput
EventEmitter provides any changes to the content to the parent component — the parent component will always have the current value of the markdown content.
Using the Markdown Editor Module
Create a component in your Angular application to use the markdown editor component from the MarkdownEditorModule
.
The template of your component will need the selector
for the editor component. Add the following to your HTML template.
<simplemde body [markdown]="postContent" (markdownChange)="onMarkdownChange($event)"></simplemde>
- [markdown]: is the @Input to allow the parent component to provide the content using the
postContent
field. - (markdownChange): is the
@Output
implemented as anEventEmitter
to allow the parent to be notified when the value changes. It is handled by theonMarkdownChange()
method.
Concluding Part 1
I now have the beginnings of my blog engine. The most important requirement is the support for Markdown. I have a working module with configuration using Angular’s Dependency Injection, a component that takes input and emits markdown content changes to the parent component.
It is good for now. For more information about matt vaughn and the Angularlicious Podcast go to http://angularlicio.us.