كيفية إنشاء تطبيق Angular بدون خادم يعمل بنظام CMS
هذا البرنامج التعليمي هو متابعة لبرنامجي التعليمي السابق حول كيفية إنشاء تطبيق Vue.js بدون خادم يعمل بنظام CMS ، ويوضح لك كيفية إنشاء تطبيق Angular بدون خادم يعمل بنظام CMS.

لقد وجدت Angular ، التي طورها مهندسو Google وصيانتها ، مكانًا عبر تطبيقات الويب الديناميكية وهي لغة مطلوبة بشكل متزايد. إنها لغة قوية وشاملة لتطوير الواجهة الأمامية وهي جاهزة لاختبار الوحدات ، مما يجعلها اللغة المفضلة للعديد من المطورين. تعمل Angular على تبسيط تجربة تطوير الواجهة الأمامية من خلال توسيع بنية HTML للسماح لك بإنشاء إمكانية إدارة المحتوى بسرعة.
بسبب بساطة Angular ، يستفيد المطورون منه بشكل متزايد لإضافة إمكانية CMS إلى مواقع الويب.
بالنسبة لمستخدمي Wordpress ، تتمثل إحدى الطرق الشائعة لدمج إمكانية إدارة المحتوى في العمل مع مكتبة wp-api-angular التي تتيح لك التفاعل مع تطبيقات Wordpress API و Angular. إذا كنت تستخدم Wordpress كمنصة CMS ، فإن استخدام Angular وواجهة برمجة تطبيقات Wordpress يمكن أن يقلل أوقات تحميل المحتوى على صفحتك.
بالنسبة لأولئك الذين لا يستخدمون Wordpress ، هناك سلالة جديدة من أنظمة إدارة المحتوى القائمة على API والتي تبسط الأمور بشكل كبير. سنناقش مثالًا واحدًا هنا.
في هذه المقالة ، سنستخدم ButterCMS كبديل لـ Wordpress ومثالًا على نظام إدارة محتوى بدون رأس قائم على SaaS يوفر لوحة تحكم CMS مستضافة وواجهة برمجة تطبيقات للمحتوى تستعلم عنها من تطبيق Angular الخاص بك. هذا يعني أنك لست بحاجة إلى تدوير أي بنية أساسية جديدة لإضافة CMS إلى تطبيق Angular الخاص بك.
سيوضح هذا البرنامج التعليمي كيفية إنشاء تطبيق Angular يعمل بنظام CMS وله صفحات تسويقية (دراسات حالة العملاء) ومدونة وأسئلة شائعة ، وكلها مدعومة عبر API. لا حاجة لخوادم!
التركيب
أولاً ، ستبدأ بتثبيت Angular cli.
npm install -g @angular/cli
قم بإعداد مشروع Angular جديد باستخدام Angular cli. بشكل افتراضي ، يستخدم angular-cli نمط CSS ، لذا فإن إضافة —-style=scss
العلم يخبر Angular CLI باستخدام SCSS بدلاً من ذلك.
ng new hello-buttercms-project --style=scsscd hello-buttercms-project
تثبيت الحزم ذات الصلة بالمواد الزاويّة والمواد الزاويّة.
npm install --save @angular/material @angular/cdknpm install --save @angular/animations
قم بتثبيت ButterCMS. قم بتشغيل هذا في سطر الأوامر الخاص بك:
npm install buttercms --save
يمكن أيضًا تحميل الزبدة باستخدام CDN:
ابدأ بسرعة
افتح المشروع في محرر الكود الذي تختاره. ضمن src / app ، قم بإنشاء دليل يسمى_services
سنقوم بإنشاء ملف يسمى butterCMS.service.js
. يتيح لك هذا الحصول على رمز API الخاص بك في مكان واحد وعدم تغييره عن طريق الخطأ.
import * as Butter from 'buttercms';
export const butterService = Butter('b60a008584313ed21803780bc9208557b3b49fbb');
ستقوم باستيراد هذا الملف إلى أي مكون تريد استخدام ButterCMS فيه.
لبدء التشغيل السريع ، انتقل إلى src/app/hello-you/hello-you.component.ts
وقم بالاستيرادbutterService
import {butterService} from '../_services';
داخل HelloYouComponent
، إنشاء طرق:
fetchPosts() { butter.post.list({ page: 1, page_size: 10 }) .then((res) => { console.log(‘Content from ButterCMS’) console.log(res) })}
الآن استدع هذه الطريقة عندما يتم تحميل المكون عن طريق إضافته إلى OnInit
رابط دورة الحياة:
ngOnInit() { this.fetchPosts();}
يجلب طلب واجهة برمجة التطبيقات هذا نموذج مشاركة مدونة. يأتي حسابك بمثال واحد ستراه في الرد. إذا تلقيت ردًا ، فهذا يعني أنه يمكنك الآن الاتصال بواجهة برمجة التطبيقات.
أضف صفحات التسويق
تتكون عملية إعداد الصفحات التي تدعم CMS من ثلاث خطوات:
- حدد نوع الصفحة
- قم بإنشاء صفحة
- الاندماج في التطبيق الخاص بك
تحديد الصفحة
First, create a Page Type to represent your Customer Case Study pages. Next, define the fields you want for your customer case studies. With your Page Type defined, you can now create the first case study page. Specify the name and URL of the page, and then populate the content of the page.

With your page defined, the ButterCMS API will return it in JSON format like this:
{ "data": { "slug": "acme-co", "fields": { "facebook_open_graph_title": "Acme Co loves ButterCMS", "seo_title": "Acme Co Customer Case Study", "headline": "Acme Co saved 200% on Anvil costs with ButterCMS", "testimonial": "We’ve been able to make anvils faster than ever before! — Chief Anvil Maker
\r\n", "customer_logo": "//cdn.buttercms.com/c8oSTGcwQDC5I58km5WV", } } }
This guide uses the Angular framework and Angular CLI to generate all the components and package our application.
Let’s get to the code.
Create new project
ng new buttercms-project --style=scsscd buttercms-projectnpm install --save @angular/material @angular/cdknpm install --save @angular/animationsnpm install -S buttercmsng serve
Your localhost:4200 should be ready to serve your Angular page.
Create typescript to export ButterCMS service
Under src/app
create a directory called _services
. Create a file called butterCMS.service.js
.
import * as Butter from 'buttercms';export const butterService = Butter('your_api_token');
Update the component routes
These components are generated by Angular CLI using:
ng g component
Under
src/app
create a file called app-routing.module.ts
import {NgModule} from '@angular/core';import {RouterModule, Routes} from '@angular/router';import {CustomerComponent} from './customer/listing/customer.listing.component';import {FaqComponent} from './faq/faq.component';import {BlogPostComponent} from './blog-post/listing/blog-post.component';import {HomeComponent} from './home/home.component';import {CustomerDetailsComponent} from './customer/details/customer.details.component';import {BlogPostDetailsComponent} from './blog-post/details/blog-post.details.component';import {FeedComponent} from './feed/feed.component';import {HelloYouComponent} from './hello-you/hello-you.component';
const appRoutes: Routes = [ {path: 'customer', component: CustomerComponent}, {path: 'customer/:slug', component: CustomerDetailsComponent}, {path: 'faq', component: FaqComponent}, {path: 'blog', component: BlogPostComponent}, {path: 'blog/:slug', component: BlogPostDetailsComponent}, {path: 'rss', component: FeedComponent}, {path: 'hello-you', component: HelloYouComponent}, {path: 'home', component: HomeComponent}, {path: '**', redirectTo: 'home'}];
@NgModule({ imports: [RouterModule.forRoot(appRoutes)], exports: [RouterModule]})export class AppRoutingModule {}
Set up the Customer List page
Under
apps/customer
type: ng g component
In the file
apps/customer/listing/customer.listing.component.ts
:
Import
butterService
In
OnInit
hook, usebutterService
to get the list of customersStore results in pages variable and markup (HTML) will be updated with the data
import {Component, OnInit} from '@angular/core';import {butterService} from '../../_services';
@Component({ selector: 'app-customer', templateUrl: './customer.listing.component.html', styleUrls: ['./customer.listing.component.scss']})
export class CustomerComponent implements OnInit { public pages: any[]; constructor() { }
ngOnInit() { butterService.page.list(‘customer_case_study’) .then((res) => { this.pages = res.data.data; }); }}
Display the results in
customer.listing.component.html
;Customers
whatshot
Set up the Customer Detail page
Under apps/customer
, type ng g component details
.
apps/customer/details/customer.details.component.ts
Create customer page
- Import
butterService
- In
OnInit
hook, usebutterService
to get the customer page given the slug in the URL path - Store results in page variable and markup (HTML) will be updated with the customer data
import {Component, OnInit} from '@angular/core';import {Observable} from 'rxjs/Observable';import {ActivatedRoute} from '@angular/router';import {butterService} from '../../_services';import {map, take} from 'rxjs/operators';
@Component({ selector: 'app-customer-details', templateUrl: './customer.details.component.html', styleUrls: ['./customer.details.component.scss']})
export class CustomerDetailsComponent implements OnInit { constructor(protected route: ActivatedRoute) { }
protected slug$: Observable; public page: any;
ngOnInit() { this.slug$ = this.route.paramMap .pipe( map(params => (params.get('slug'))) );
this.slug$.pipe( take(1)) .subscribe(slug => { butterService.page.retrieve('customer_case_study', slug) .then((res) => { this.page = res.data.data; }).catch((res) => { console.log(res); }); }); } }
Display the results in customer.details.component.html
{{page.fields.headline}}
Testimonials
You can now navigate to the Customer Page via the list of all Customer Pages or directly via URL.
Add a knowledge base
Set up content fields
Let’s suppose you want to add a CMS to a static FAQ page with a title and a list of questions with answers.
Making your content dynamic with Butter is a two-step process:
- Setup custom content fields in Butter
- Integrate the fields into your application
To setup custom content fields, first sign in to the Butter dashboard.
Create a new workspace or click on an existing one. Workspaces let you organize content fields in a friendly way for content editors and have no effect on development or the API. For example, a real-estate website might have a workspace called “Properties” and another called “About Page”.

Once you’re in a workspace click the button to create a new content field. Choose the “Object” type and name the field “FAQ Headline.”

After saving, add another field, but this time choose the “Collection” type and name the field FAQ Items
.
On the next screen, setup two properties for items in the collection.
Now go back to your workspace and update your heading and FAQ items.
Integrate your app
Create FAQ Component
Under apps
type: ng g component faq
apps/faq/faq.component.ts
Set up onInit hook to load FAQ
import {Component, OnInit} from '@angular/core';import {butterService} from '../_services';
@Component({ selector: 'app-faq', templateUrl: './faq.component.html', styleUrls: ['./faq.component.scss']})
export class FaqComponent implements OnInit { constructor() {}
public faq: any = { items: [], title: 'FAQ' };
ngOnInit() { butterService.content.retrieve(['faq_headline', 'faq_items']) .then((res) => { console.log(res.data.data); this.faq.title = res.data.data.faq_headline; this.faq.items = res.data.data.faq_items; }); }}
Display the result
; {{item.question}}
The values entered in the Butter dashboard will immediately update the content in our app.
Blogging
To display posts, you need to create a
/blog
route in your app and fetch blog posts from the Butter API, as well as a /blog/:slug
route to handle individual posts.
See the API reference for additional options such as filtering by category or author. The response also includes some metadata we’ll use for pagination.
Set up Blog Homepage
Under
apps/blog-post
, type: ng g component listing
.
apps/blog-post/listing/blog-post.listing.component.ts
Update component to get all posts:
Import
butterService
Get all post
onInit
import {Component, OnInit} from '@angular/core';import {butterService} from '../../_services';
@Component({ selector: 'app-blog-post', templateUrl: './blog-post.component.html', styleUrls: ['./blog-post.component.scss']})export class BlogPostComponent implements OnInit { public posts: any[];
constructor() { }
ngOnInit() { butterService.post.list({ page: 1, page_size: 10}).then((res) => { console.log(res.data) this.posts = res.data.data; }); }}
Display the result:
Blog Posts;
;
;
whatshot
Set up Blog Post page
Under apps/blog-post
, type: ng g component details
apps/blog-post/details/blog-post.details.component.ts
- Import
butterService
- In
OnInit
hook, usebutterService
to get the blog-post post given the slug in the URL path - Store results in post variable and markup (HTML) will be updated with the customer data
import {Component, OnInit, ViewEncapsulation} from '@angular/core';import {Observable} from 'rxjs/Observable';import {ActivatedRoute} from '@angular/router';import {butterService} from '../../_services';import {map, take} from 'rxjs/operators';
@Component({ selector: 'app-blog-post-details', templateUrl: './blog-post.details.component.html', styleUrls: ['./blog-post.details.component.scss'], encapsulation: ViewEncapsulation.None})
export class BlogPostDetailsComponent implements OnInit {
constructor(protected route: ActivatedRoute) { }
protected slug$: Observable; public post = { meta: null, data: null};
ngOnInit() { this.slug$ = this.route.paramMap .pipe( map(params => (params.get('slug'))) );
this.slug$.pipe( take(1)) .subscribe(slug => { butterService.post.retrieve(slug) .then((res) => { this.post = res.data; }).catch((res) => { console.log(res); }); }); }}
{{post.data.title}} < ;> ; {{post.data.author.first_name}} {{post.data.author.last_name}}
Now your app has a working blog that can be updated easily in the ButterCMS dashboard.
Categories, tags, and authors
Use Butter’s APIs for categories, tags, and authors to feature and filter content on your blog.
List all categories and get posts by category
Call these methods on the onInit()
lifecycle hook:
methods: { ... getCategories() { butter.category.list() .then((res) => { console.log('List of Categories:') console.log(res.data.data) }) }, getPostsByCategory() { butter.category.retrieve('example-category', { include: 'recent_posts' }) .then((res) => { console.log('Posts with specific category:') console.log(res) }) } }, created() { ... this.getCategories() this.getPostsByCategory()}
getCategories() { butter.category.list() .then((res) => { console.log(‘List of Categories:’) console.log(res.data.data) }) }, getPostsByCategory() { butter.category.retrieve(‘example-category’, { include: ‘recent_posts’ }) .then((res) => { console.log(‘Posts with specific category:’) console.log(res) }) }},created() { … this.getCategories() this.getPostsByCategory()}