{"id":3989,"date":"2017-03-28T18:00:46","date_gmt":"2017-03-28T14:00:46","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=3989"},"modified":"2026-01-23T14:48:44","modified_gmt":"2026-01-23T11:48:44","slug":"create-meteor-app-dhtmlxscheduler","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/create-meteor-app-dhtmlxscheduler\/","title":{"rendered":"How To Create Meteor App with dhtmlxScheduler"},"content":{"rendered":"<p>We&#8217;ve <a href=\"\/\/dhtmlx.com\/blog\/use-dhtmlxscheduler-meteorjs-based-apps\/\">already described<\/a> how to integrate our <a href=\"\/\/dhtmlx.com\/docs\/products\/dhtmlxScheduler\/\">Scheduler component<\/a> into meteor app using special packages. Though it was easiest way to integrate dhtmlxScheduler, we now release this article that shows you how to integrate dhtmlxScheduler with Meteor JavaScript framework manually in case you want to get it more flexible for some specific customization.<\/p>\n<p>Before we start our integration, make sure that Meteor platform is installed according to Meteor. If everything is OK, let&#8217;s move on and prepare our app.<\/p>\n<p>You can jump to a complete <a href=\"https:\/\/github.com\/DHTMLX\/meteor-scheduler-app\" target=\"_blank\"><strong>Scheduler with Meteor demo<\/strong><\/a> that is already available on GitHub.<\/p>\n<h4>4 steps to prepare our app<\/h4>\n<p><strong>Step 1.<\/strong> First of all, we need to create an app. For this, run the following command in your terminal:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">meteor create scheduler<span class=\"sy0\">-<\/span>meteor<\/div><\/div>\n<p>Here is how we run the app:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">cd scheduler<span class=\"sy0\">-<\/span>meteor<br \/>\nmeteor<\/div><\/div>\n<p>Now if we open <strong>http:\/\/127.0.0.1:3000\/<\/strong> we should see a page like this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3994\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/welcome-to-meteor-app.png\" alt=\"welcome to meteor app\" width=\"800\" height=\"571\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/welcome-to-meteor-app.png 800w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/welcome-to-meteor-app-300x214.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/welcome-to-meteor-app-768x548.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p><strong>Step 2.<\/strong> Then its time to install dhtmlxScheduler. To do this, run the following command:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">meteor npm install dhtmlx<span class=\"sy0\">-<\/span>scheduler <span class=\"sy0\">--<\/span>save<\/div><\/div>\n<p>Let&#8217;s also install the helper package to load static files. For this purpose run the next:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">meteor add runisland<span class=\"sy0\">:<\/span>static<span class=\"sy0\">-<\/span>assets<\/div><\/div>\n<p>Create file static-assets.json in the application root and put the following code to it to define folders with scheduler images to load as static files:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"st0\">&quot;map&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs\/&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs_contrast_black\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs_contrast_black\/&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs_contrast_white\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs_contrast_white\/&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs_dhx_terrace\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs_dhx_terrace\/&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs_flat\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs_flat\/&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"st0\">&quot;node_modules\/dhtmlx-scheduler\/codebase\/imgs_glossy\/&quot;<\/span><span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;imgs_glossy\/&quot;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p><strong>Step 3.<\/strong> Create imports\/ui\/scheduler folders and create scheduler.html file inside it. Here we&#8217;ll define template with necessary blocks for scheduler.<\/p>\n<p>Add the following code to it:<\/p>\n<div class=\"codecolorer-container html4strict default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"html4strict codecolorer\">&nbsp;<\/div><\/div>\n<div id=\"scheduler_here\" class=\"dhx_cal_container\" style=\"width: 100%; height: 600px;\"><\/div>\n<p>&nbsp;<\/p>\n<p>Also we need to create scheduler.js in this folder. Now we need to put scheduler initialization code to it:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"st0\">'dhtmlx-scheduler\/codebase\/dhtmlxscheduler.js'<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw5\">import<\/span> <span class=\"st0\">'dhtmlx-scheduler\/codebase\/dhtmlxscheduler.css'<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>import &#8216;.\/scheduler.html&#8217;;<\/p>\n<p>Template.scheduler.onRendered(function () {<br \/>\nlet container = this.$(&#8220;.dhx_cal_container&#8221;)[0];<br \/>\nscheduler.init(container, new Date(2017, 2, 16), &#8220;week&#8221;);<br \/>\n});<\/p>\n<p>Here we&#8217;re initializing scheduler after template rendering.<\/p>\n<p><strong>Step 4.<\/strong> Open client\/main.html file and put the following code to add our scheduler template to body:<\/p>\n<div class=\"codecolorer-container html4strict default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"html4strict codecolorer\">scheduler-meteor<\/div><\/div>\n<p>{{&gt; scheduler}}<\/p>\n<p>The next step is to open client\/main.js file and import our scheduler.js to entry point:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"br0\">&#123;<\/span> Template <span class=\"br0\">&#125;<\/span> from <span class=\"st0\">'meteor\/templating'<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>import &#8216;..\/imports\/ui\/scheduler\/scheduler.js&#8217;;<br \/>\nimport &#8216;.\/main.html&#8217;;<\/p>\n<p>Now if we run our application, we should see an empty scheduler on the page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3993\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/empty-scheduler.png\" alt=\"empty-scheduler\" width=\"900\" height=\"423\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/empty-scheduler.png 900w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/empty-scheduler-300x141.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/empty-scheduler-768x361.png 768w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<h4>Data Saving<\/h4>\n<p>Create API folder inside imports folder, and then create events.js module inside. Here we create new mongo collection for events and export it.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"br0\">&#123;<\/span> Mongo <span class=\"br0\">&#125;<\/span> from <span class=\"st0\">'meteor\/mongo'<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>export const Events = new Mongo.Collection(&#8216;events&#8217;);<\/p>\n<p>We should import this module on the server to create MongoDB collection and allow client to get data. Open server\/main.js and add following this:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"st0\">'..\/imports\/api\/events.js'<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Also we should update our client side. Now we want to set up two-way sync between scheduler and our mongo collection, so each time scheduler data is modified &#8211; it will be immediately reflected in mongo and vice versa. Open imports\/ui\/scheduler\/scheduler.js to put the following:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw5\">import<\/span> <span class=\"st0\">'dhtmlx-scheduler\/codebase\/dhtmlxscheduler.js'<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw5\">import<\/span> <span class=\"st0\">'dhtmlx-scheduler\/codebase\/dhtmlxscheduler.css'<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>import &#8216;.\/scheduler.html&#8217;;<\/p>\n<p>import {Events} from &#8216;..\/..\/api\/events.js&#8217;;<\/p>\n<p>Template.scheduler.onRendered(function () {<br \/>\nlet container = this.$(&#8220;.dhx_cal_container&#8221;)[0];<br \/>\nscheduler.init(container, new Date(2017, 2, 16), &#8220;week&#8221;);<br \/>\nlet parseEventData = (data)=&gt; {<br \/>\nlet event = {};<\/p>\n<p>for (let property in data) {<br \/>\nif (property == &#8220;_id&#8221;) {<br \/>\nevent[&#8220;id&#8221;] = data[property];<br \/>\n}<br \/>\nelse {<br \/>\nevent[property] = data[property];<br \/>\n}<br \/>\n}<\/p>\n<p>return event;<br \/>\n};<\/p>\n<p>let serializeEvent = (event) =&gt; {<br \/>\nlet data = {};<\/p>\n<p>for (let property in event) {<br \/>\nif (property.charAt(0) == &#8220;_&#8221; || property == &#8220;id&#8221;) continue;<\/p>\n<p>data[property] = event[property];<br \/>\n}<\/p>\n<p>return data;<br \/>\n};<\/p>\n<p>let eventsCursor = Events.find();<br \/>\nlet events = [];<br \/>\nlet renderTimeout = null;<\/p>\n<p>eventsCursor.observe({<br \/>\nadded(data) {<br \/>\nlet event = parseEventData(data);<br \/>\nif (!scheduler.getEvent(event.id)) {<br \/>\nevents.push(event);<br \/>\n}<\/p>\n<p>clearTimeout(renderTimeout);<br \/>\nrenderTimeout = setTimeout(()=&gt; {<br \/>\nscheduler.parse(events, &#8220;json&#8221;);<br \/>\nevents = [];<br \/>\n}, 5);<br \/>\n},<\/p>\n<p>changed(data) {<br \/>\nlet event = parseEventData(data);<br \/>\nlet originalEvent = scheduler.getEvent(event.id);<\/p>\n<p>if (!originalEvent) return;<\/p>\n<p>for (let key in event) {<br \/>\noriginalEvent[key] = event[key];<br \/>\n}<\/p>\n<p>scheduler.updateView();<br \/>\n},<\/p>\n<p>removed(data){<br \/>\nlet event = parseEventData(data);<br \/>\nif (scheduler.getEvent(event.id)) {<br \/>\nscheduler.deleteEvent(event.id);<br \/>\n}<br \/>\n}<br \/>\n});<\/p>\n<p>scheduler.attachEvent(&#8220;onEventAdded&#8221;, (eventId, event) =&gt; {<br \/>\nlet data = serializeEvent(event);<br \/>\nlet newId = Events.insert(data);<br \/>\nscheduler.changeEventId(eventId, newId);<br \/>\n});<\/p>\n<p>scheduler.attachEvent(&#8220;onEventChanged&#8221;, (eventId, event) =&gt; {<br \/>\nlet data = serializeEvent(event);<br \/>\nEvents.update(eventId, {$set: data});<br \/>\n});<\/p>\n<p>scheduler.attachEvent(&#8220;onEventDeleted&#8221;, (eventId) =&gt; {<br \/>\nEvents.remove(eventId);<br \/>\n});<br \/>\n});<\/p>\n<p>Also here we add scheduler events handlers to put events changes to collection. So, when event is added, changed or deleted, we add corresponding changes to collection.<\/p>\n<p>Now we can add some initial events. Do so, run the following code in your terminal:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">meteor mongo<br \/>\ndb.<span class=\"me1\">events<\/span>.<span class=\"me1\">insert<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span>_id<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;1&quot;<\/span><span class=\"sy0\">,<\/span> start_date<span class=\"sy0\">:<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">2017<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">16<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">8<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> end_date<span class=\"sy0\">:<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">2017<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">16<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">12<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> text<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Test Event 1&quot;<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ndb.<span class=\"me1\">events<\/span>.<span class=\"me1\">insert<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span>_id<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;2&quot;<\/span><span class=\"sy0\">,<\/span> start_date<span class=\"sy0\">:<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">2017<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">17<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">9<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> end_date<span class=\"sy0\">:<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">2017<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">17<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">13<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> text<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Test Event 2&quot;<\/span><span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Now we get a working example. It should load data from the server side and save changes.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3995\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/scheduler-data-loading.png\" alt=\"scheduler-data-loading\" width=\"900\" height=\"423\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/scheduler-data-loading.png 900w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/scheduler-data-loading-300x141.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2017\/03\/scheduler-data-loading-768x361.png 768w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p>Thus you have a demo of a real-time scheduling calendar based on Meteor JS Framework and dhtmlxScheduler (feature-rich booking\/appointment calendar). <a href=\"https:\/\/github.com\/DHTMLX\/meteor-scheduler-app\" target=\"_blank\">Grab the demo from GitHub<\/a> to study the integration and customize according to your needs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We&#8217;ve already described how to integrate our Scheduler component into meteor app using special packages. Though it was easiest way to integrate dhtmlxScheduler, we now release this article that &#8230;<\/p>\n","protected":false},"author":2,"featured_media":3992,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,71,1,38],"tags":[33,14,44,15],"class_list":["post-3989","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-posts-for-codeproject-com","category-tutorials","category-uncategorized","category-visible","tag-all-posts","tag-tips","tag-meteor","tag-dhtmlxscheduler"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/3989","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/comments?post=3989"}],"version-history":[{"count":5,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/3989\/revisions"}],"predecessor-version":[{"id":14960,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/3989\/revisions\/14960"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/3992"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=3989"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=3989"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=3989"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}