[Tutorial] How to install Angular CLI and show Steemit Posts in an Angular Web App

in #utopian-io7 years ago (edited)

In this tutorial you will learn

<ul> <li>how to install Angular CLI on your machine <li>initialize your app using Angular CLI <li>create a Post class to describe particular posts <li>create a PostDataService service to retrieve posts from steemit <li>use the base AppComponent component to bring it all together and display the steemit posts <li>style your app with CSS <li>push your app to GitHub Pages <p dir="auto">You will need an environment capable of runing <a href="https://nodejs.org" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Node.js and <a href="https://www.npmjs.com" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">NPM. <p dir="auto">This tutorial is suggested for basic to intermediate users. <p dir="auto">Before we start, let's take a sneak peek at the end result. <p dir="auto">See it in action on <a href="https://learnsteem.github.io/steemit-posts/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">GitHub Pages: Steemit Posts or clone the repository from <a href="https://github.com/learnsteem/steemit-posts" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">GitHub: Steemit Posts and run it on your machine, or checkout the following screenshot. <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521550864/boyoonftbceypnc00i5r.png" alt="Angular App Steemit Posts Listing" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521550864/boyoonftbceypnc00i5r.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1521550864/boyoonftbceypnc00i5r.png 2x" /> <p dir="auto">Ready? Let’s get started! <blockquote> <p dir="auto"><strong>Note: Angular starting from version 2, is a completely new framework built on ideas and lessons learned from AngularJS which is version 1. <h2>Install Angular CLI <p dir="auto">The most comfortable way to start an Angular app is to use the <a href="https://cli.angular.io/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Angular command line interface (CLI) <p dir="auto">To install Angular CLI in your NodeJS environment, open your console and run <pre><code>> npm install -g @angular/cli <p dir="auto">after the installation, the <code>ng command will be globally available on your system. <p dir="auto">To verify that the installation went through successfully, run: <pre><code>> ng version <p dir="auto">it will print something like this <pre><code>Angular CLI: 1.7.2 Node: 9.6.1 OS: linux x64 Angular: 5.2.7 <p dir="auto">Now Angular CLI is installed on your machine, let’s head over and create your app. <h2>Initialize your app using Angular CLI <p dir="auto">The Angular CLI makes it easy to create an application that already works, right out of the box. Run: <pre><code>> ng new steem-posts <p dir="auto">Now, navigate into the project directory <pre><code>> cd steem-posts <p dir="auto">and generate your first class. <h2>Generate the Post class <p dir="auto">Angular CLI uses <a href="https://www.typescriptlang.org/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">TypeScript, so we can use a class to describe the Post items. <p dir="auto">Let’s generate a <code>Post class using Angular CLI <pre><code>> ng generate class post <p dir="auto">which will create <pre><code>src/app/post.ts <p dir="auto">Let's open the new class file and add the logic <pre><code>export class Post { title = ''; author = ''; body = ''; created = ''; images: Array<string> = []; tags: Array<string> = []; net_votes = 0; pending_payout_value = 0; constructor(values = {}) { Object.assign(this, values); } } <p dir="auto">In the <code>Post class you define that every <code>Post instance will contain these attributes <pre><code>title: string, title of the post author: string, author of the post body: string, the actual content created: string, creation date of the post images: array of strings, images belong to the post tags: array of strings, associated tags net_votes: number, post upvotes count pending_payout_value: number, value of the post <p dir="auto">The attributes have initial values assigned already, so you know the types by declaration and don't have to specify them additionally. Except <code>images and <code>tags, there you define the array content type. <p dir="auto">Along the class attributes, you also define the constructor that adds the ability to define values during instantiation, so you can create new <code>Post instances just like this <pre><code>let post = new Post({ title: 'Beyond Awesome!', author: 'RhinoTheHamster', body: 'Rhino is awesome! He's so awesome! He is... he is beyond awesome! He's bey-awesome!', // … }); <p dir="auto">Now that you have a descriptive <code>Post class, let’s move on and generate a <code>PostDataService service to retrieve posts from steemit. <h2>Generate the PostDataService service <p dir="auto">The <code>PostDataService will handle the API requests and manage the <code>Post items. <p dir="auto">Let’s install the steem API using NPM, so we have an interface to the steemit data <pre><code>> npm install --save steem <p dir="auto">and generate the <code>PostDataService service using Angular CLI <pre><code>> ng generate service post-data <p dir="auto">which will create <pre><code>src/app/post-data.service.spec.ts src/app/post-data.service.ts <p dir="auto">Angular CLI also generated the spec file, which you can use to define unit tests. Let’s skip them for now and move straight to the service file and add the logic we need <pre><code>import { Injectable } from '@angular/core'; import { api as steemapi } from 'steem'; import { Post } from './post'; @Injectable() export class PostDataService { constructor() { } getPosts(): Promise<Post[]> { return new Promise((resolve, reject) => { steemapi.getDiscussionsByCreated({ limit: 10 }, (error, result) => { if (error) { reject(error); } else { const posts = []; result.map((post) => { const meta = JSON.parse(post.json_metadata); posts.push(new Post({ title: post.title, author: post.author, body: post.body, created: post.created, images: meta.image, tags: meta.tags, net_votes: post.net_votes, pending_payout_value: post.pending_payout_value, })); }); resolve(posts); } }); }); } } <p dir="auto">Et voilà! Now that we have a <code>PostDataService, let’s move on to the display part. <h2>Hands on the AppComponent component <p dir="auto">Angular CLI automatically generated <code>AppComponent for you when you created the project. You can find it’s parts here <pre><code>src/app/app.component.css src/app/app.component.html src/app/app.component.ts src/app/app.component.spec.ts <p dir="auto">Let’s edit <code>src/app/app.component.html and replace the dummy content with <pre><code><article *ngFor="let post of posts; let even = even; let odd = odd" [ngClass]="{ odd: odd, even: even }"> <div class="image" [style.background-image]="'url('+(post.images? post.images[0] : '')+')'"></div> <div class="body"> <h1 [innerText]="post.title"></h1> <div class="meta"> By <a href="https://steemit.com/@{{post.author}}" target="_blank">{{post.author}}</a> &bull; {{post.created}} &bull; ${{post.pending_payout_value}} &bull; {{post.net_votes}} votes </div> <div class="tags" *ngIf="post.tags.length > 0"> <a *ngFor="let tag of post.tags" href="https://steemit.com/trending/{{tag}}" target="_blank">{{tag}}</a> </div> <p [innerText]="(post.body.length > 300)? (post.body | slice:0:300)+'..': (post.body)"></p> </div> </article> <p dir="auto">Have a look at Angular’s template syntax and directives. It makes our life a lot easier. Here's an excerpt <ul> <li><code>*ngFor="..." - iterates an array of items and creates elements dynamically from a template element; exports values that can be aliased to local variables: e.g. <code>even: boolean, <code>odd: boolean <li><code>*ngIf="expression" - conditionally includes a template based on the value of an expression <li><code>[property]="expression" - sets the property of an element to the value of expression <li><code>[class.class-name]="expression" - adds <code>class-name to the elements list of CSS class names when the value of <code>expression is truthy <li><code>[style.property]="expression" - sets an elements CSS style property to the value of <code>expression <blockquote> <p dir="auto">Want to know more? Head over to the <a href="https://angular.io/docs/ts/latest/guide/template-syntax.html" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">official Angular template syntax documentation. <p dir="auto">Now let's add the logic or the so called <strong>expression context. The expression context in this case is the component instance which is an instance of the class <code>AppComponent. So let's dive into the file <code>src/app/app.component.ts and add the logic. <pre><code>import { Component, OnInit } from '@angular/core'; import { PostDataService } from './post-data.service'; import { Post } from './post'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], providers: [PostDataService] }) export class AppComponent implements OnInit { posts: Post[] = []; constructor(private postDataService: PostDataService) { } public ngOnInit() { this.postDataService.getPosts().then((posts) => { this.posts = posts; }).catch((error) => { console.log(error); }); } } <p dir="auto">What do we have here? Let's have look <p dir="auto">At first we import the <code>Post class and the <code>PostDataService service and define <code>PostDataService in the <code>providers array of the <code>Compontent decorator, so the dependency injector (DI) of <code>AppComponent knows, it has to create only a single instance whenever we ask for the service. <blockquote> <p dir="auto">Wanna learn more about Angular’s dependency injection system? Head over to <a href="https://angular.io/guide/dependency-injection" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Angular’s official dependency injection documentation. <p dir="auto">Now in the <code>constructor of <code>AppComponent we instruct the instance to provide <code>PostDataService service as an private attribute of the <code>AppComponent instance. <p dir="auto">We also added a public property called <code>posts of type <code>Post, declared it's initial value to be an empty array and added the public method <code>ngOnInit() to ask <code>PostDataService to pull in steemit posts and assign it to <code>this.post, overwritting the empty array. Now when Angular initializes <code>AppComponent, <code>ngOnInit() gets executed and the train starts to move :) <p dir="auto">Let's try it, run <pre><code>> ng serve <p dir="auto">this will start a local develompent server, which you can access by navigating your browser to <code>http://localhost:4200/ <p dir="auto">When you change a file, your local develompent server will send a signal to your browser, so it can automatically reload the application. <p dir="auto">Ok! Let's check the result.. Missing something? Oh yah! We miss the styling. <h2>Style your app <p dir="auto">Angular loads stylesheets which belong to components automatically, so just edit <code>src/app/app.component.css and add <pre><code>@import url(https://fonts.googleapis.com/css?family=Roboto|Open+Sans); article { display: flex; margin: 0 auto 10px; height: 300px; width: 800px; font-family: 'Open Sans', sans-serif; font-size: 14px; line-height: 21px; border-radius: 3px; box-shadow: 0 3px 7px -3px rgba(0, 0, 0, 0.3); } article .image { position: relative; width: 300px; height: 300px; background-image: url('https://placeimg.com/300/300/tech'); background-size: cover; background-repeat: no-repeat; background-position: center center; } article .body { width: 500px; padding: 20px; overflow: hidden; background-color: #fff; } article .body h1 { margin: 0 0 10px; font-family: 'Roboto', sans-serif; font-size: 28px; font-weight: 700; line-height: 32px; letter-spacing: 2px; } article .body .meta, article .body .tags { font-family: 'Open Sans', sans-serif; font-size: 14px; font-weight: 400; color: #9a9a9a; } article .body .tags { margin-top: -2px; } article .body .tags a::before { content: ', '; } article .body .tags a:first-child::before { content: ''; } article .body > p { position: relative; margin: 15px 0 0; } article .body > p::before { content: ""; position: absolute; top: -10px; left: 0; height: 5px; width: 50px; background-color: #689F38; } article.odd .image { order: 2; } article.odd .image::before, article.even .image::after { content: ""; position: absolute; top: 0px; width: 22px; height: 100%; background-color: #fff; transform: skewX(-4deg); } article.odd .image::before { left: -11px; } article.even .image::after { right: -11px; } <p dir="auto">Now open the application's global stylesheet <code>src/styles.css and add <pre><code>html, body { background-color: #f1f1f1; } a { color: #689f38; text-decoration: none; } <p dir="auto">Great! Save the files and watch the LiveReload system doing it's magic :) <p dir="auto">Before we end this tutorial, let's take advantage of an awesome feature of Angular CLI. <h2>Deploy your app to GitHub Pages <p dir="auto">With Angular CLI it's super simple to deploy your work. The following command tells Angular CLI to build a static version of your app and save it to the <code>docs/ directory in the root of your project. <pre><code>> ng build --prod --output-path docs --base-href steemit-posts <p dir="auto">Now push your project to GitHub into your repository's master branch and change the settings of this repository to serve from <code>master branch /docs folder by doing this: <ol> <li>On GitHub, navigate to your GitHub Pages site's repository. <li>Under your repository name, click Settings. <li>Scroll to "GitHub Pages" and use the Select source drop-down menu to select <code>master branch /docs folder as your GitHub Pages publishing source. <blockquote> <p dir="auto"><strong>Note: Need more input on GitHub Pages and how to configure a publishing source for GitHub Pages? Read <a href="https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Configuring a publishing source for GitHub Pages <p dir="auto">When all goes right, you should now see your new app hosted on GitHub Pages, like this <p dir="auto"><a href="https://learnsteem.github.io/steemit-posts/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://learnsteem.github.io/steemit-posts/ <p dir="auto">That's bey-awesome! Isnt't it? <h2>That's it :) <p dir="auto">Feel free to clone the source of this tutorial from <a href="https://github.com/learnsteem/steemit-posts" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">GitHub: Steemit Posts <p dir="auto">Thanks for reading, hope you enjoyed it :) <p dir="auto"><br /><hr /><em>Posted on <a href="https://utopian.io/utopian-io/@aley/tutorial-how-to-install-angular-cli-and-show-steemit-posts-in-an-angular-web-app" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Utopian.io - Rewarding Open Source Contributors<hr /><p>
Sort:  

this clearly tutorial what i looking for a long time. hope can help me thank you very much

Changed repository to angular:

Submissions that include a GitHub repository with additional materials (like code samples), should be linked to the repository of the original project discussed in the tutorial and not the supplementary repository created for the contribution. Links to the supplementary repository for the post should be included in the submission post.

Please change your tutorial to follow template provided in the editor:

Failure to apply the templates provided in the editor for each category may lead to rejection. The standard contribution submission templates should be followed when detailing your contribution. However, templates can be edited and extended as long as the formatting is clear.

Hi @laxam. Thanks for approving the tutorial. I've changed the text to include Requirements and Difficulty.

About changing the repo to angular: I would not suggest changing the repo to angular, since angular cli is a bootstrapper and development tool for angular projects. It copies template files from the angular cli repo, so it's easy to start a new project. So in this case angular cli is not the "original project" and the tutorial is not a "supplementary repository" but a whole new project created with tools from angular cli.

Hi @aley. Thanks for including Requirements and Difficulty.

I would argue that this tutorial teaches reader how to use angular and not steemit-posts. If you view it as a new project - there is a development section for such cases. You can send future contributions there if they follow the rules for that section.

@laxam, so in case I would make a tutorial for "how to program in javascript" I would add the javascript language repo as original project? It's a bit confusing, but I guess I got the idea. Thanks.

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @aley I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • This is your first accepted contribution here in Utopian. Welcome!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x