Angular एप्लिकेशन का मालिक है
कैनवास के चारों ओर सब कुछ: उपयोगकर्ता कौन है, उन्हें क्या करने की अनुमति है, और परिणाम कहां जाता है।
- रूटिंग
- प्रमाणीकरण
- आवेदन UI
- उपयोगकर्ता
- अनुमतियां
- बिलिंग
- API परत
- आवेदन की स्थिति
ड्रैग-एंड-ड्रॉप पेज बिल्डर, CMS संपादक, लैंडिंग पेज बिल्डर, ईमेल संपादक और व्हाइट-लेबल विज़ुअल संपादन अनुभव बनाने के लिए ओपन-सोर्स GrapesJS विज़ुअल एडिटर को Angular एप्लिकेशन में एकीकृत करें।
26k+
GitHub सितारे
1.4M+
npm डाउनलोड/माह
100+
प्लगइन्स GJS.Market पर
$0
लाइसेंस शुल्क
स्टॉक GrapesJS बिल्ड - वह संपादक जो आपको मानक प्रीसेट के साथ 'grapesjs.init()' से मिलता है, इससे पहले कि कोई प्लगइन जोड़ा जाए। दाएं पैनल से एक ब्लॉक खींचें, उसका चयन करें, और स्टाइल मैनेजर में इसकी टाइपोग्राफी और रिक्ति को संपादित करें।
grapesjs.com से एक तृतीय-पक्ष पृष्ठ लोड करता है। जब तक आप क्लिक नहीं करते तब तक कुछ भी अनुरोध नहीं किया जाता है।
ये लाइव GrapesJS बिल्ड हैं, न कि Angular डेमो - और यही बात है। GrapesJS एक कंटेनर तत्व में प्रस्तुत करता है जो पूरी तरह से मालिक है, इसलिए कैनवास, ब्लॉक, स्टाइल मैनेजर, उत्तरदायी पूर्वावलोकन, परिसंपत्ति बीनने वाला और इतिहास पूर्ववत करें जिसे आप नीचे चलाते हैं, एक बार Angular घटक उस कंटेनर को होस्ट करता है।
Angular आपके एप्लिकेशन को शक्ति प्रदान करता है। GrapesJS दृश्य संपादन अनुभव को शक्ति प्रदान करता है। जो सामने आता है वह HTML, CSS और एक प्रोजेक्ट JSON दस्तावेज़ है जिसे आपका अपना बैकएंड स्टोर करता है।
GrapesJS फ्रेमवर्क-अज्ञेयवादी है और इसे Angular अनुप्रयोगों में एकीकृत किया जा सकता है। आप संपादक को Angular जीवनचक्र हुक के माध्यम से प्रारंभ करते हैं, संपादक इंस्टेंस को अपने नियंत्रण में रखते हैं, GrapesJS ईवेंट को Angular एप्लिकेशन लॉजिक से कनेक्ट करते हैं, और अपने स्वयं के बैकएंड के माध्यम से प्रोजेक्ट डेटा को बनाए रखते हैं।
कोई आधिकारिक Angular आवरण नहीं है। GrapesJS परियोजना एक React आवरण और कोई Angular समकक्ष नहीं रखती है, इसलिए Angular एकीकरण का अर्थ है एक घटक लिखना - नीचे दिए गए उदाहरण में लगभग तीस पंक्तियाँ - या अपने स्वयं के गुणों के आधार पर किसी तृतीय-पक्ष पैकेज का मूल्यांकन करना।
काम करने वाले उदाहरण पर जाएंGrapesJS विज़ुअल एडिटिंग इंजन है। Angular एप्लिकेशन फ्रेमवर्क है। लगभग हर एकीकरण समस्या जो लोगों को मिलती है, वह उनमें से एक से दूसरे का काम करने की उम्मीद करने से आती है, इसलिए उनके बीच की रेखा के बारे में स्पष्ट होना उचित है।
कैनवास के चारों ओर सब कुछ: उपयोगकर्ता कौन है, उन्हें क्या करने की अनुमति है, और परिणाम कहां जाता है।
कैनवास के अंदर सब कुछ: क्या खींचा जा सकता है, चुना जा सकता है, स्टाइल किया जा सकता है और निर्यात किया जा सकता है।
Angular आपका आवेदन है। GrapesJS आपका विज़ुअल एडिटिंग इंजन है।
एक निर्भरता और एक स्टाइलशीट। GrapesJS अपने स्वयं के CSS को शिप करता है, और इसके बिना संपादक माउंट करता है लेकिन अनस्टाइल मार्कअप के रूप में प्रस्तुत करता है - जो कि पहला एकीकरण टूटा हुआ दिखने का सबसे आम कारण है।
1 - निर्भरता जोड़ें
npm install grapesjs2 - स्टाइलशीट रजिस्टर करें
// angular.json → projects.<app>.architect.build.options
{
"styles": [
"src/styles.css",
"node_modules/grapesjs/dist/css/grapes.min.css"
]
}स्टाइलशीट को angular.json में पंजीकृत करना इसे विश्व स्तर पर लागू करता है। यदि संपादक एक आलसी-लोड किए गए मार्ग पर रहता है और आप हर जगह CSS के लिए भुगतान नहीं करना चाहते हैं, तो इसे इसके बजाय संपादक घटक की अपनी स्टाइलशीट के अंदर आयात करें।
GrapesJS को संलग्न करने के लिए एक वास्तविक तत्व की आवश्यकता होती है, और यह उस तत्व को मापता है क्योंकि यह प्रारंभ होता है। ngOnInit में टेम्पलेट अभी तक प्रस्तुत नहीं किया गया है, इसलिए एक @ViewChild संदर्भ अभी भी अपरिभाषित है और कॉल पूरी तरह से विफल हो जाती है। ngAfterViewInit Angular द्वारा घटक का दृश्य बनाने के बाद चलता है, जो कि कंटेनर मौजूद होने का पहला क्षण है। वही तर्क नीचे दी गई स्टाइलशीट में ऊंचाई नियम की व्याख्या करता है: बिना किसी हल की ऊंचाई वाला एक तत्व एक संपादक बनाता है जो त्रुटि के बिना आरंभ करता है और कुछ भी प्रदर्शित नहीं करता है।
इससे पहले कि आप घटक लिखें
GrapesJS आपके द्वारा सौंपे गए तत्व की सामग्री को बदल देता है। उस तत्व के अंदर Angular टेम्पलेट सामग्री को प्रस्तुत न करें और इसके तहत किसी भी चीज़ से न बंधें।
होस्ट तत्व को आरंभीकरण से पहले एक हल की गई ऊंचाई की आवश्यकता होती है। एक शून्य-ऊंचाई वाला कंटेनर एक संपादक को माउंट करता है जिसे आप नहीं देख सकते हैं।
संपादक के लिए एक ही संदर्भ रखें और इसे ngOnDestroy में नष्ट कर दें। एक मार्ग पर दो लाइव उदाहरण कीबोर्ड शॉर्टकट पर लड़ेंगे।
grapesjs पैकेज अपनी TypeScript परिभाषाओं को शिप करता है, इसलिए Editor, Component और ProjectData एक अलग @types पैकेज के बिना आयात योग्य हैं।
तीन फ़ाइलें, कुछ भी उत्पन्न नहीं हुआ, कुछ भी छिपा नहीं है। उन्हें Angular एप्लिकेशन में कॉपी करें और आपके पास एक मार्ग पर एक कार्यशील दृश्य संपादक है। इस पृष्ठ पर बाद में सब कुछ - भंडारण, संपत्ति, कस्टम घटक, प्लगइन्स - इस घटक के अतिरिक्त है, न कि इसका पुनर्लेखन।
// editor.component.ts
import {
AfterViewInit,
Component,
ElementRef,
OnDestroy,
ViewChild,
} from '@angular/core';
import grapesjs, { type Editor } from 'grapesjs';
@Component({
selector: 'app-editor',
templateUrl: './editor.component.html',
styleUrl: './editor.component.css',
})
export class EditorComponent implements AfterViewInit, OnDestroy {
// Resolved by the time ngAfterViewInit runs — that is the whole reason
// initialisation lives there and not in ngOnInit.
@ViewChild('editorHost') private host!: ElementRef<HTMLDivElement>;
private editor?: Editor;
ngAfterViewInit(): void {
this.editor = grapesjs.init({
container: this.host.nativeElement,
height: '100%',
width: 'auto',
fromElement: false,
// No persistence yet. Wire your own API before shipping — see Storage.
storageManager: false,
blockManager: {
blocks: [
{
id: 'section',
label: 'Section',
category: 'Layout',
content: '<section class="section"><h2>Headline</h2></section>',
},
{
id: 'text',
label: 'Text',
category: 'Basic',
content: { type: 'text', content: 'Edit me' },
},
{ id: 'image', label: 'Image', category: 'Basic', content: { type: 'image' } },
],
},
});
}
ngOnDestroy(): void {
// GrapesJS owns DOM nodes, document listeners and an undo stack. Angular
// removes the host element; only destroy() releases the rest.
this.editor?.destroy();
this.editor = undefined;
}
}<!-- editor.component.html -->
<!-- GrapesJS takes this element over completely. Do not render Angular
content inside it — the editor owns everything below #editorHost. -->
<div class="editor-shell">
<div #editorHost class="editor-host"></div>
</div>/* editor.component.css */
.editor-shell {
display: block;
block-size: 100dvh;
}
/* GrapesJS measures its container at init. A host with no resolved height
produces an editor that mounts successfully and renders nothing. */
.editor-host {
block-size: 100%;
}यही संपूर्ण एकीकरण है। फिर से पढ़ने लायक हिस्से दो जीवनचक्र हुक हैं: ngAfterViewInit में आरंभीकरण क्योंकि कंटेनर को पहले मौजूद होना चाहिए, और destroy() ngOnDestroy में क्योंकि Angular होस्ट तत्व को हटाने से दस्तावेज़ से जुड़ा GrapesJS जारी नहीं होता है।
संपादक अधिकांश अनुप्रयोगों में सबसे भारी चीज है जिसमें एक होता है। इसे आलसी रूप से लोड किए गए मार्ग के पीछे रखने से यह हर उस उपयोगकर्ता के लिए प्रारंभिक बंडल से बाहर रहता है जो इसे कभी नहीं खोलता है।
// app.routes.ts — the editor is the heaviest route in the app. Load it last.
import type { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', loadComponent: () => import('./home/home.component').then((m) => m.HomeComponent) },
{
path: 'pages/:id/edit',
loadComponent: () => import('./editor/editor.component').then((m) => m.EditorComponent),
},
];संपादक का जीवनकाल घटक से बंधा होना चाहिए। चार टुकड़े उस काम को करते हैं, और उनमें से प्रत्येक गायब होने पर पहचानने योग्य तरीके से विफल हो जाता है।
कंटेनर तत्व का संदर्भ प्राप्त करता है। इसे टेम्पलेट संदर्भ चर द्वारा क्वेरी करें, न कि CSS चयनकर्ता द्वारा, इसलिए मार्कअप का एक रिफैक्टर चुपचाप लुकअप को तोड़ नहीं सकता है।
पहला हुक जो घटक के दृश्य के बाद चलता है, मौजूद है। यहां आरंभ करें। पहले आरंभ करने से आपको एक अपरिभाषित तत्व संदर्भ मिलता है।
इसे एक निजी क्षेत्र में, या एक सेवा में रखें यदि कहीं और टूलबार घटक को कमांड ट्रिगर करने की आवश्यकता होती है। बाद में आप जो कुछ भी करते हैं वह इस एक ऑब्जेक्ट से होकर गुजरता है।
editor.destroy() पर कॉल करें। यह संपादक के DOM को हटा देता है, अपने दस्तावेज़-स्तरीय श्रोताओं को अलग करता है और पूर्ववत स्टैक को त्याग देता है। इसे छोड़ना एक रिसाव है जो नेविगेशन से बच जाता है।
संपादक कंटेनर मौजूद होने से पहले GrapesJS प्रारंभ न करें।
यह वह त्रुटि है जो अधिकांश "GrapesJS Angular" रिपोर्ट में काम नहीं करती है। ngOnInit में, और किसी भी कंस्ट्रक्टर में, दृश्य नहीं बनाया गया है - कंटेनर संदर्भ अपरिभाषित है और आरंभीकरण फेंकता है। यदि कंटेनर एक @if ब्लॉक या एक आस्थगित दृश्य के अंदर है, तो ngAfterViewInit भी पर्याप्त नहीं है: तब तक प्रतीक्षा करें जब तक कि वह शाखा वास्तव में आपके शुरू होने से पहले प्रस्तुत न हो जाए।
GrapesJS बड़ी संख्या में श्रोताओं को अपने कैनवास से जोड़ता है और उन्हें लगातार आग लगाता है जबकि एक घटक को खींचा या आकार दिया जा रहा है। एक ज़ोन-आधारित Angular एप्लिकेशन में उन श्रोताओं में से हर एक परिवर्तन-पहचान पास शेड्यूल करता है, भले ही आपके घटक ट्री में कुछ भी नहीं बदला हो।
// editor.component.ts (excerpt)
import { Component, NgZone, inject, signal } from '@angular/core';
export class EditorComponent {
private readonly zone = inject(NgZone);
readonly selectedTag = signal('');
readonly savedAt = signal<Date | null>(null);
private mount(host: HTMLElement): void {
// The canvas fires pointer events continuously while a block is being
// dragged. Creating the editor outside the zone keeps those from
// scheduling a change-detection pass on every frame.
this.zone.runOutsideAngular(() => {
const editor = grapesjs.init({ container: host, height: '100%' });
// Re-enter only where editor state has to become Angular state.
editor.on('component:selected', (component) => {
this.zone.run(() => this.selectedTag.set(component.get('tagName') ?? ''));
});
editor.on('storage:end:store', () => {
this.zone.run(() => this.savedAt.set(new Date()));
});
this.editor = editor;
});
}
}
// Zoneless applications (provideZonelessChangeDetection) have no zone to
// leave. Set signals from the same editor events and drop NgZone entirely.आरंभीकरण के समय एक बार ज़ोन छोड़ दें। उन विशिष्ट घटनाओं पर संकीर्ण रूप से पुनः प्रवेश करें, जिन्हें आपका इंटरफ़ेस सुनता है। प्रत्येक संपादक कॉलबैक को NgZone.run() में लपेटने से ठीक वही परिवर्तन-पता लगाने वाला मंथन वापस मिल जाता है जिससे बचने के लिए आपने क्षेत्र छोड़ा था।
संपादक ब्राउज़र में चलता है। GrapesJS वास्तविक DOM से अपना कैनवास बनाता है - यह तत्वों को मापता है, एक iframe बनाता है और दस्तावेज़ श्रोताओं को संलग्न करता है - इसलिए आरंभीकरण ब्राउज़र संदर्भ में होना चाहिए और सर्वर रेंडर के दौरान नहीं चलना चाहिए। वे मार्ग जो केवल प्रकाशित आउटपुट प्रदर्शित करते हैं, अप्रभावित हैं: यह सादा HTML और CSS है और सर्वर पर किसी और चीज़ की तरह रेंडर करता है।
// editor.component.ts — browser-only initialisation
import {
AfterViewInit,
Component,
ElementRef,
OnDestroy,
PLATFORM_ID,
ViewChild,
inject,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import type { Editor } from 'grapesjs';
export class EditorComponent implements AfterViewInit, OnDestroy {
@ViewChild('editorHost') private host!: ElementRef<HTMLDivElement>;
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
private editor?: Editor;
async ngAfterViewInit(): Promise<void> {
if (!this.isBrowser) return;
// A dynamic import keeps the editor out of the server bundle and off the
// critical path of every route that never opens it.
const { default: grapesjs } = await import('grapesjs');
this.editor = grapesjs.init({ container: this.host.nativeElement });
}
ngOnDestroy(): void {
this.editor?.destroy();
}
}हाल के Angular संस्करण एक रेंडर हुक प्रदान करते हैं जिसका कॉलबैक केवल ब्राउज़र प्लेटफ़ॉर्म पर चलता है और सर्वर पर कभी नहीं। जहां यह उपलब्ध है, यह प्लेटफ़ॉर्म चेक के बिना समान गारंटी व्यक्त करता है, और यह स्वाभाविक रूप से सिग्नल-आधारित दृश्य प्रश्नों के साथ जुड़ता है।
// The same guard, expressed with the render hook instead of a platform check.
import { Component, ElementRef, afterNextRender, viewChild } from '@angular/core';
import type { Editor } from 'grapesjs';
@Component({ selector: 'app-editor', template: '<div #editorHost></div>' })
export class EditorComponent {
private readonly host = viewChild.required<ElementRef<HTMLDivElement>>('editorHost');
private editor?: Editor;
constructor() {
// afterNextRender callbacks run on browser platforms only — they never
// execute on the server, so no isPlatformBrowser check is needed.
afterNextRender(async () => {
const { default: grapesjs } = await import('grapesjs');
this.editor = grapesjs.init({ container: this.host().nativeElement });
});
}
}चुनने से पहले जांचें कि आपका Angular संस्करण इनमें से किसका समर्थन करता है। दोनों पैटर्न एक ही नियम को लागू करने के लिए मौजूद हैं - संपादक ब्राउज़र में इनिशियलाइज़ करता है और कहीं और नहीं। angular.dev
एक पेज बिल्डर एक विशेषता नहीं है। यह नौ उप-प्रणालियाँ हैं जिन्हें एक दूसरे से सहमत होना पड़ता है, और GrapesJS सभी नौ जहाजों को भेजता है। यह सिंहावलोकन है; उत्पाद-स्तरीय निर्णय - मूल्य निर्धारण, भूमिकाएँ, टेम्पलेट्स, प्रकाशन वर्कफ़्लो - नीचे लिंक किए गए समर्पित गाइड से संबंधित हैं।
संपादन योग्य सतह, अपने स्वयं के iframe में प्रस्तुत की गई है ताकि पृष्ठ शैलियाँ आपके व्यवस्थापक UI में लीक न हो सकें।
प्रत्येक तत्व के पीछे टाइप किया गया मॉडल: यह क्या है, यह क्या स्वीकार करता है, और यह किन सेटिंग्स को उजागर करता है।
पैलेट उपयोगकर्ता खींचते हैं। एक ब्लॉक एक घटक प्रकार में मैप की गई सामग्री का एक नामित टुकड़ा है।
CSS संपादन पैनल, कॉन्फ़िगर करने योग्य है कि किसी दिए गए उपयोगकर्ता को किस गुण को बदलने की अनुमति है।
छवि और मीडिया चयन। इसके पीछे अपलोड समापन बिंदु आपका है, इसलिए यहां प्लगइन्स ज्यादातर इसे एक प्रदाता से जोड़ते हैं।
लोड करें और सहेजें। GrapesJS अनुबंध को परिभाषित करता है और आपके API को कॉल करता है - दृढ़ता ही आपके आवेदन का है।
नामित, कॉल करने योग्य क्रियाएं — पूर्ववत करें, पूर्वावलोकन करें, निर्यात करें, और कुछ भी जो आप टूलबार बटन के लिए स्वयं को पंजीकृत करते हैं।
कैनवास के उत्तरदायी ब्रेकपॉइंट का पूर्वावलोकन और स्टाइल किया जा सकता है।
संपादक का अपना क्रोम - बटन, टूलबार और क्षेत्र, सभी बदली जा सकती हैं यदि संपादक मौजूदा शेल के अंदर बैठता है।
नौ में से आठ संपादक के साथ या एक प्लगइन के साथ जहाज करते हैं। जो अपरिहार्य रूप से आपका है वह भंडारण है - जो कि आपके उपयोगकर्ताओं, आपकी अनुमतियों और आपके डेटाबेस के बारे में भी जानना है।
एक पूर्ण Angular पेज बिल्डर बनाएंयदि संपादक को एप्लिकेशन में कहीं और से पहुंचा जा सकता है - शेल में एक टूलबार, एक पृष्ठ सूची, एक पूर्वावलोकन फलक - एक इंजेक्टेबल सेवा में आरंभीकरण को स्थानांतरित करें और घटकों को सीधे संपादक के बजाय उस पर बात करने दें।
कैनवास एक वास्तविक iframe है। यह जानबूझकर है: पृष्ठ शैलियाँ आपके व्यवस्थापक इंटरफ़ेस में लीक नहीं हो सकती हैं और आपकी एप्लिकेशन शैलियाँ संपादित किए जा रहे पृष्ठ में लीक नहीं हो सकती हैं, जो कि बिल्कुल वही अलगाव है जो आप चाहते हैं जब दोनों अलग-अलग लोगों द्वारा डिज़ाइन किए जाते हैं।
तीन कलाकृतियाँ, और उन्हें मिलाने से वास्तविक डेटा हानि होती है। प्रोजेक्ट डेटा संपादन योग्य दस्तावेज़ है; HTML और CSS प्रकाशित परिणाम हैं। वे विनिमेय नहीं हैं, क्योंकि निर्यात डिजाइन द्वारा हानिपूर्ण है।
एक JSON दस्तावेज़ जिसमें घटकों, शैलियों, पृष्ठों और संपत्तियों को रखा जाता है। यह वही है जिसे आप संग्रहीत करते हैं ताकि एक संपादक पृष्ठ को ठीक उसी तरह फिर से खोल सके जैसे इसे छोड़ा गया था। इसे सत्य के स्रोत के रूप में मानें।
पृष्ठ के लिए मार्कअप के रूप में इसे परोसा जाएगा। इसे प्रोजेक्ट डेटा के साथ स्टोर करें ताकि प्रकाशन को कभी भी संपादक को बूट न करना पड़े, और इसलिए संपादक अनुपलब्ध होने पर भी एक पृष्ठ प्रस्तुत हो सकता है।
संपादक ने उस पृष्ठ के लिए जो शैलियाँ तैयार की हैं, वे उन नियमों के अनुरूप हैं जिन्हें वह प्रबंधित करता है। इसे HTML के साथ परोसें - दोनों दो फ़ाइलों में विभाजित एक आउटपुट हैं।
// Three outputs, three different jobs. Do not use one where you need another.
const projectData = editor.getProjectData(); // editable state → store this
const html = editor.getHtml(); // markup → publish this
const css = editor.getCss(); // styles → publish this
// Reopening a saved project restores components, styles, pages and assets.
// Re-parsing exported HTML does not — it loses everything not in the markup.
editor.loadProjectData(projectData);निर्यात किए गए HTML को वापस संपादक में बदलना प्रोजेक्ट डेटा का विकल्प नहीं है: यह घटक प्रकार, traits, पृष्ठ संरचना और कुछ भी खो देता है जो मार्कअप में व्यक्त नहीं किया जा सकता था। GrapesJS एक संपादक है, न कि CMS या बैकएंड - जहां कलाकृतियां जाती हैं, और बाद में उनके साथ क्या होता है, यह आपके आवेदन का निर्णय है।
// project-storage.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
import type { Editor, ProjectData } from 'grapesjs';
@Injectable({ providedIn: 'root' })
export class ProjectStorage {
private readonly http = inject(HttpClient);
/** Registers a named storage the editor can then autosave into. */
register(editor: Editor, projectId: string): void {
editor.Storage.add('gjs-api', {
load: () =>
firstValueFrom(this.http.get<ProjectData>(`/api/projects/${projectId}`)),
store: async (data) => {
await firstValueFrom(
this.http.put(`/api/projects/${projectId}`, {
project: data, // what the editor reopens
html: editor.getHtml(), // what the site renders
css: editor.getCss(),
})
);
},
});
}
}// Point the editor at the storage you just registered.
this.storage.register(editor, projectId);
grapesjs.init({
container: host,
storageManager: {
type: 'gjs-api', // the name passed to Storage.add()
autosave: true,
autoload: true,
stepsBeforeSave: 5, // batch edits instead of a request per keystroke
},
});संपादक कभी भी आपके डेटाबेस से बात नहीं करता है। यह आपके द्वारा पंजीकृत दो विधियों को कॉल करता है, जो HttpClient को कॉल करता है, जो आपके API को उसी इंटरसेप्टर के तहत कॉल करता है और एप्लिकेशन में हर दूसरे अनुरोध के रूप में प्रमाणीकरण करता है।
संपादन योग्य दस्तावेज़ संग्रहीत करें
उपयोगकर्ता द्वारा फिर से खोले जाने वाले रिकॉर्ड के रूप में getProjectData() आउटपुट जारी रखें। निर्यात किए गए HTML और CSS को एक ही लेखन में संग्रहीत करें ताकि प्रकाशन में कोई दूसरा दौर यात्रा न हो।
बैच लिखता है, उन्हें स्ट्रीम न करें
autosave stepsBeforeSave के साथ संपादनों के एक विस्फोट को एक अनुरोध में बदल देता है। Tune चरणों की गिनती आपके API में करें, डेमो डिफ़ॉल्ट के लिए नहीं।
ऑटोलोड, या स्पष्ट रूप से लोड करें
autoload संपादक को शुरू करने देता है। इसके बजाय स्पष्ट रूप से लोड हो रहा है आपको अपना खुद का स्पिनर दिखाने और संपादक के बजाय एक एप्लिकेशन त्रुटि के रूप में 403 को संभालने के लिए एक जगह देता है।
इतिहास सर्वर-साइड रखें
पूर्ववत स्टैक ब्राउज़र में रहता है और टैब के साथ मर जाता है। यदि उपयोगकर्ताओं को कल के पृष्ठ को पुनर्स्थापित करने की आवश्यकता है, तो यह आपके डेटाबेस में एक संस्करण तालिका है, जो स्टोर पर लिखी गई है।
प्रकाशन से अलग बचत
सेव ड्राफ़्ट को अपडेट करता है. प्रकाशन लाइव रूट के लिए एक विशिष्ट संस्करण को बढ़ावा देता है — एक अलग समापन बिंदु, अपनी स्वयं की अनुमति जांच के साथ.
परिसंपत्ति प्रबंधक एक पिकर है, फ़ाइल सेवा नहीं। इसे अपने Angular एप्लिकेशन में एक समापन बिंदु पर इंगित करें और यह वहां फाइलें पोस्ट करेगा; उसके बाद सब कुछ - सत्यापन, भंडारण, आकार बदलना, वितरण - लागू करना आपका है, जो आपके पास पहले से मौजूद मीडिया लाइब्रेरी का पुनः उपयोग करना संभव बनाता है।
// Assets go to your endpoint, under your auth — GrapesJS only POSTs files.
grapesjs.init({
container: host,
assetManager: {
upload: `/api/projects/${projectId}/assets`,
uploadName: 'files',
multiUpload: true,
credentials: 'include',
headers: { 'X-Requested-With': 'XMLHttpRequest' },
// Off by default is the safer choice: base64 images end up inside saved
// markup and make every page row grow without limit.
embedAsBase64: false,
// Returning false aborts the upload before the request leaves the browser.
beforeUpload: (files: File[]) =>
files.every((file) => file.size <= MAX_UPLOAD_BYTES && ALLOWED_TYPES.has(file.type)),
},
});
editor.on('asset:upload:start', () => this.uploading.set(true));
editor.on('asset:upload:end', () => this.uploading.set(false));
editor.on('asset:upload:error', (error) => this.uploadError.set(String(error)));इनमें से कोई भी एक विशेष बैकएंड निर्धारित नहीं करता है। S3, Cloudinary, एक लारवेल डिस्क या सर्वर पर एक फ़ोल्डर सभी एक ही अनुबंध को पूरा करते हैं: एक फ़ाइल स्वीकार करें, एक यूआरएल लौटाएं।
एक घटक प्रकार को पंजीकृत करना यह है कि संपादक आपके उत्पाद के बारे में कैसे सीखता है। एक कस्टम प्रकार को अपना स्वयं का सेटिंग पैनल, अपने स्वयं के ड्रैग-एंड-ड्रॉप नियम और पैलेट में एक ब्लॉक मिलता है - इसलिए सामग्री टीमें कच्चे divs के बजाय आपके डोमेन से अवधारणाओं के साथ काम करती हैं।
// pricing-table.type.ts — an application-specific building block.
import type { Editor } from 'grapesjs';
export function registerPricingTable(editor: Editor): void {
editor.Components.addType('pricing-table', {
// Lets the editor recognise the type again when a saved page is reparsed.
isComponent: (el) => el.classList?.contains('pricing-table'),
model: {
defaults: {
tagName: 'section',
attributes: { class: 'pricing-table' },
droppable: false,
// Traits become the right-hand settings panel for this component.
traits: [
{ type: 'text', name: 'plan', label: 'Plan name' },
{ type: 'number', name: 'price', label: 'Price' },
{ type: 'checkbox', name: 'featured', label: 'Highlight' },
],
components: `
<h3 data-gjs-type="text">Team</h3>
<p data-gjs-type="text">$29 / month</p>
`,
},
},
});
// A block is how the component reaches the user: one entry in the palette.
editor.Blocks.add('pricing-table', {
label: 'Pricing table',
category: 'Commerce',
content: { type: 'pricing-table' },
});
}विशिष्ट अनुप्रयोग-विशिष्ट घटक
दो चीजें एक कस्टम प्रकार को उपयोगी बनाती हैं। isComponent संपादक को आपके प्रकार को फिर से पहचानने देता है जब एक सहेजे गए पृष्ठ को फिर से पार्स किया जाता है, और traits एक गैर-तकनीकी उपयोगकर्ता वास्तव में संपादित करता है। दोनों एक साधारण घटक के लिए भी लिखने लायक हैं।
एक ही एकीकरण इन सभी को रेखांकित करता है। उनके बीच क्या परिवर्तन होता है कि आप किन ब्लॉकों को पंजीकृत करते हैं, आप किन शैलियों को उजागर करते हैं, और आउटपुट कहां प्रकाशित होता है।
आपके Angular एप्लिकेशन के अंदर एक दृश्य पृष्ठ संपादन अनुभव, आपके अपने ब्लॉक, आपके स्वयं के ब्रांड बाधाओं और आपके स्वयं के प्रकाशन प्रवाह के साथ।
एक पूर्ण Angular पेज बिल्डर बनाएंसामग्री टीमों को टिकट दाखिल करने के बजाय पृष्ठों को विज़ुअल रूप से संपादित करने दें। संपादक उस व्यवस्थापक एप्लिकेशन का एक मार्ग बन जाता है जिसका वे पहले से उपयोग करते हैं।
हेडलेस CMS पैटर्न देखेंपुनः प्रयोज्य विपणन अनुभाग और लेआउट, कॉपी के हर परिवर्तन के लिए तैनाती के बिना एक विपणन टीम द्वारा इकट्ठे किए गए।
लैंडिंग पेज बिल्डर पैटर्नईमेल टेम्प्लेट को नेत्रहीन रूप से बनाएं और प्रबंधित करें, MJML प्रीसेट प्रोडक्शन मार्कअप के साथ जो वास्तविक ईमेल क्लाइंट से बचता है।
ईमेल के लिए GrapesJSआपके SaaS उत्पाद के अंदर एक ब्रांडेड संपादक, संपादक के अपने क्रोम के साथ बदल दिया गया है ताकि यह किसी तृतीय-पक्ष टूल के बजाय आपके इंटरफ़ेस के रूप में पढ़ा जा सके।
संपादक को व्हाइट-लेबल करेंउपयोगकर्ताओं को दृश्य संपादन दें जबकि आपका एप्लिकेशन डेटाबेस में समाप्त होने वाले HTML और CSS पर नियंत्रण रखता है।
HTML ड्रैग-एंड-ड्रॉप बिल्डर बनाना सीखेंएक प्लगइन एक फ़ंक्शन है जो संपादक उदाहरण प्राप्त करता है, इसलिए यहां कुछ भी Angular-विशिष्ट नहीं है - GrapesJS के लिए प्रकाशित कुछ भी Angular घटक के अंदर काम करता है। ये चार अंतराल हैं जो संपादक माउंट के बाद पहले टीमें हिट करती हैं।
उपयोगकर्ता क्या खींचते हैं। एक नंगे संपादक के पास पैलेट में लगभग कुछ भी नहीं होता है, इसलिए यह पहली चीज है जो हर एकीकरण जोड़ता है।
श्रेणी ब्राउज़ करेंशुरुआती पैलेट - ब्लॉक एक नया संपादक पहली बार चलाने पर गायब है।
संपादक में Tailwind कक्षाएं, यदि आपका Angular ऐप पहले से ही Tailwind शिप करता है।
Bootstrap 5 घटकों को खींचने योग्य ब्लॉक के रूप में देखें।
हाथ से निर्मित मार्कअप के बजाय कॉन्फ़िगर करने योग्य हेडर अनुभाग।
दृढ़ता, autosave और बहु-परियोजना प्रबंधन - ऊपर के अनुभाग से भंडारण अनुबंध के चारों ओर की परत।
श्रेणी ब्राउज़ करेंएक संपादक में कई परियोजनाएँ, एक परियोजना सूची UI के साथ।
ब्राउज़र में स्थानीय दृढ़ता - ड्राफ्ट और ऑफ़लाइन संपादन के लिए उपयोगी।
दुर्घटना या आकस्मिक नेविगेशन के बाद सहेजे न गए कार्य को पुनर्प्राप्त करता है।
भंडारण एक bespoke समापन बिंदु के बजाय एक Directus उदाहरण द्वारा समर्थित।
बेहतर इनलाइन टेक्स्ट एडिटिंग और वास्तविक फॉर्म घटक। दोनों ऐसी क्षमताएं हैं जो उपयोगकर्ता मानते हैं कि वे अंतर्निहित हैं।
श्रेणी ब्राउज़ करेंअंतर्निहित समृद्ध टेक्स्ट एडिटर को CKEditor 5 से बदल देता है।
अंतर्निहित समृद्ध टेक्स्ट एडिटर को TinyMCE 6 से बदल देता है।
डिफ़ॉल्ट रिच टेक्स्ट टूलबार पर अतिरिक्त स्वरूपण नियंत्रण.
वास्तविक इनपुट, सत्यापन traits और सबमिशन सेटिंग्स के साथ घटकों को बनाएं।
मीडिया प्रदाता, निर्यात प्रारूप और ईमेल प्रीसेट, उन सतहों के लिए जिनमें एक बिल्डर बढ़ता है।
श्रेणी ब्राउज़ करेंCloudinary परिसंपत्ति बैकएंड के रूप में, जिसमें परिवर्तन भी शामिल हैं।
पृष्ठ को ZIP, HTML, CSS और संपत्ति के रूप में निर्यात करता है।
MJML ब्लॉक करता है ताकि वही संपादक ईमेल-सुरक्षित मार्कअप तैयार कर सके।
अभिगम्यता और SEO संपादक के अंदर जांच, किसी पृष्ठ के प्रकाशित होने से पहले।
प्लगइन श्रेणियां
Angular में एक विज़ुअल एडिटर बनाना संभव है - यह एक ज्ञात मात्रा में काम है, असंभव नहीं। सवाल यह है कि आप उत्पाद के जीवनकाल के लिए इसके कौन से हिस्से रखना चाहते हैं।
| योग्यता | अपने आप को बनाएं | GrapesJS |
|---|---|---|
| कैंवस | निर्माण | शामिल |
| खींचें और छोड़ें | निर्माण | शामिल |
| अवयव | निर्माण | शामिल |
| ब्लॉक | निर्माण | शामिल |
| बिछाना | निर्माण | शामिल |
| संपत्ति | निर्माण | शामिल |
| भंडार | निर्माण | एक्स्टेंसिबल - आप समापन बिंदुओं की आपूर्ति करते हैं |
| प्लगइन्स | एक पारिस्थितिकी तंत्र का निर्माण करें | Plugin वास्तुकला |
| Angular एकीकरण | आपके ऐप का मूल निवासी | एक घटक के माध्यम से एकीकृत करें |
| लाइसेंस | तुम्हारा | BSD-3-Clause — $0 to use |
"बिल्ड" कोई आलोचना नहीं है - इनमें से हर एक निर्माण योग्य है। यह एक बयान है कि बाद में इसे कौन बनाए रखता है।
इस तालिका में तथ्यों को फिर से सत्यापित किया गया 2026-09-02।
Angular आपको एप्लिकेशन फ्रेमवर्क देता है। GrapesJS आपको विज़ुअल एडिटिंग इंजन देता है।
नहीं, और यह समझने योग्य है कि सवाल क्यों आता है। GrapesJS एक आधिकारिक React रैपर प्रकाशित करता है, इसलिए डेवलपर्स यथोचित रूप से Angular समकक्ष की उम्मीद करते हैं। एक नहीं है। यह तीन दृष्टिकोण छोड़ देता है, और अधिकांश टीमों के लिए पहला सही उत्तर है।
घटक को स्वयं लिखें - इस पृष्ठ पर एक लगभग तीस पंक्तियों का है। आप जीवनचक्र, परिवर्तन-पहचान रणनीति और अपग्रेड पथ के मालिक हैं, और आपके ऐप और संपादक API के बीच कोई तीसरा पक्ष नहीं है।
सामुदायिक पैकेज मौजूद हैं और पहले घंटे को छोटा कर सकते हैं। किसी भी निर्भरता का मूल्यांकन करें: जांचें कि इसे कौन बनाए रखता है, कौन से Angular और GrapesJS संस्करण घोषित करता है, और यह हाल ही में कैसे प्रकाशित हुआ था।
एक बार जब कई घटकों को संपादक की आवश्यकता होती है - एक टूलबार, एक पृष्ठ सूची, एक पूर्वावलोकन फलक - आरंभीकरण को एक इंजेक्शन सेवा में ले जाते हैं। यह एक सीम के साथ सीधा एकीकरण है, और यह संपादक को आपके घटक वृक्ष से बाहर रखता है।
GrapesJS संगठन एक React आवरण और कोई Angular पैकेज नहीं रखता है। आपको मिलने वाली कोई भी Angular लाइब्रेरी तृतीय-पक्ष है, चाहे वह कितनी भी उपयोगी क्यों न हो - इसे एक निर्भरता विकल्प के रूप में मानें, न कि GrapesJS के हिस्से के रूप में।
एक डेमो एक घटक है। एक उत्पाद चार परतों का होता है, और संपादक उनमें से केवल एक होता है। यह वह आकार है जिस पर अधिकांश टीमें एक बार संपादक के पीछे वास्तविक उपयोगकर्ता होने के बाद अभिसरण करती हैं।
शेल, राउटर, और एक आलसी-लोड किया गया मार्ग जो संपादक का मालिक है।
एक बार कॉन्फ़िगर किया गया, आरंभीकरण पर: कौन से घटक मौजूद हैं, क्या खींचा जा सकता है, क्या स्टाइल किया जा सकता है।
संपादक और आपके Angular के बीच API परत - और एकमात्र स्थान प्राधिकरण निर्णय क्लाइंट-साइड किए जाते हैं।
कलाकृतियां कहां रहती हैं, और जहां हर अनुमति वास्तविक रूप से लागू की जाती है।
इस आरेख में दूसरे स्तर को छोड़कर कुछ भी GrapesJS-विशिष्ट नहीं है। यही बात है: संपादक एक साधारण Angular एप्लिकेशन में एक घटक है, और बाकी वह आर्किटेक्चर है जिसे आपने वैसे भी बनाया होगा।
देखें कि टीमें इसे उत्पाद के रूप में कैसे पैकेज करती हैंसंपादक आपके एप्लिकेशन के अंदर चलने वाले सॉफ़्टवेयर का एक बड़ा टुकड़ा है। ये वे स्थान हैं जहां वास्तव में कुछ खर्च होता है।
संपादन मार्ग खुलने पर संपादक बनाएं, एप्लिकेशन प्रारंभ में नहीं। जो उपयोगकर्ता कभी संपादन नहीं करते हैं उन्हें इसके लिए कभी भुगतान नहीं करना चाहिए।
एक गतिशील आयात GrapesJS को प्रारंभिक बंडल से बाहर रखता है, जो इस सूची में सबसे बड़ा लीवर है।
runOutsideAngular के साथ संपादक बनाएं ताकि कैनवास पॉइंटर ईवेंट हर फ्रेम पर परिवर्तन का पता लगाने को ट्रिगर न करें।
संपादक को init पर एक पूर्ण मीडिया लाइब्रेरी न सौंपें। अपने API के माध्यम से पेगिनेट करें और पिकर के अनुरोध के अनुसार संपत्ति लोड करें।
बहुत गहरी या बहुत दोहराव वाली पृष्ठ संरचनाएं चयन, स्टाइल और पूर्ववत धीमी गति से बनाती हैं। गहरे नेस्टेड रैपर पर घटकों को प्राथमिकता दें।
stepsBeforeSave का उपयोग करें ताकि संपादनों का एक विस्फोट प्रति कीस्ट्रोक अनुरोध के बजाय एक अनुरोध बन जाए।
इनमें से कोई भी वादा की गई संख्या के साथ नहीं आता है। पहले और बाद में अपने स्वयं के संपादक मार्ग को मापें - प्रत्येक प्रभाव का आकार आपके ब्लॉक, आपके पृष्ठों और आपके API पर निर्भर करता है।
एक विज़ुअल एडिटर उपयोगकर्ताओं को HTML के लेखकों में बदल देता है जो आपका एप्लिकेशन तब कार्य करता है। संपादक से निकलने वाली हर चीज को उपयोगकर्ता इनपुट के रूप में मानें, क्योंकि यह वही है जो यह है।
Editor आउटपुट में मनमाना मार्कअप हो सकता है, जिसमें स्क्रिप्ट भी शामिल है यदि कस्टम कोड ब्लॉक सक्षम हैं। सर्वर-साइड को उसके लेखक के अलावा किसी और को परोसने से पहले सैनिटाइज करें।
सर्वर पर प्रकार और आकार की जाँच करें, न कि केवल beforeUpload में। अपलोड को वेब रूट के बाहर स्टोर करें और उन्हें एक अलग मूल से परोसें।
लोड और सेव मार्ग साधारण API समापन बिंदु हैं। उन्हें एप्लिकेशन में बाकी सभी चीज़ों की तरह ही प्रमाणीकरण की आवश्यकता होती है।
Angular UI में एक प्रकाशन बटन छिपाना प्रस्तुति है। जो चेक मायने रखता है वह समापन बिंदु पर है।
संग्रहीत प्रोजेक्ट JSON के साथ छेड़छाड़ की जा सकती है। यह मानने के बजाय इसे लोड पर मान्य करें कि यह आपके द्वारा लिखा गया दस्तावेज़ है।
एक बहु-किरायेदार उत्पाद में, सर्वर पर सत्र से प्रोजेक्ट के स्वामी को प्राप्त करें - अनुरोध निकाय में कभी भी आईडी से नहीं।
बारह चीजें जो एक मार्ग से एक कार्यशील डेमो को अलग करती हैं, वास्तविक उपयोगकर्ताओं को दी जा सकती हैं।
निर्भरता जोड़ी गई और स्टाइलशीट पंजीकृत, विश्व स्तर पर या संपादक घटक में।
अनुभाग पढ़ेंgrapesjs.init() ngAfterViewInit में चलता है, एक हल की गई ऊंचाई वाले कंटेनर के खिलाफ।
अनुभाग पढ़ेंeditor.destroy() में ngOnDestroy, बिना लीक के दूर और वापस नेविगेट करके सत्यापित किया जाता है।
अनुभाग पढ़ेंसंरक्षित इसलिए सर्वर रेंडर के दौरान कुछ भी नहीं चलता है, इसके स्थान पर एक प्लेसहोल्डर होता है।
अनुभाग पढ़ेंएक नामित भंडारण पंजीकृत, autosave ट्यून किया गया, और प्रोजेक्ट JSON HTML और CSS के साथ संग्रहीत किया गया।
अनुभाग पढ़ेंअपलोड आपके समापन बिंदु पर इंगित किया गया है, base64 एम्बेडिंग बंद, दोनों तरफ सत्यापन।
अनुभाग पढ़ेंआपके उत्पाद के अपने बिल्डिंग ब्लॉक्स traits और पैलेट प्रविष्टियों के साथ प्रकारों के रूप में पंजीकृत हैं।
अनुभाग पढ़ेंBlocks, समृद्ध पाठ और निर्यात को संचित करने के बजाय जानबूझकर चुना गया।
अनुभाग पढ़ेंकौन संपादित कर सकता है, कौन प्रकाशित कर सकता है - सर्वर पर लागू, UI में परिलक्षित होता है।
अनुभाग पढ़ेंकिसी पृष्ठ को सहेजने और आगंतुकों को सेवा देने के बीच सर्वर-साइड सैनिटाइजेशन।
अनुभाग पढ़ेंEditor अपवादों को आपकी बाकी Angular त्रुटियों के समान स्थान पर रिपोर्ट किया गया है।
डिवाइस मैनेजर ने न केवल डेस्कटॉप ब्राउज़र विंडो में बल्कि टच डिवाइस पर व्यायाम किया।
अनुभाग पढ़ेंओपन-सोर्स विज़ुअल एडिटर से शुरुआत करें, इसे अपने Angular एप्लिकेशन से कनेक्ट करें, और इसे प्लगइन्स और अपने उत्पाद की ज़रूरत के एकीकरण के साथ विस्तारित करें।
पैकेज स्थापित करें, घटक की प्रतिलिपि बनाएँ, और आज दोपहर Angular मार्ग पर एक संपादक चलाएँ।
शुरू हो जाओब्लॉक, भंडारण, समृद्ध पाठ, संपत्ति, निर्यात और ईमेल - वे टुकड़े जिन्हें आप अन्यथा स्वयं लिख रहे होंगे।
प्लगइन्स ब्राउज़ करेंसंपादक को अपने एप्लिकेशन की एक विशेषता के रूप में स्कोप करें: भूमिकाएं, टेम्पलेट, प्रकाशन और संस्करण।
एक संक्षिप्त प्रारंभ करेंAngular के साथ एप्लिकेशन बनाएं। GrapesJS के साथ विज़ुअल एडिटर बनाएं। इसे GJS.Market प्लगइन्स के साथ विस्तारित करें।