{"id":24558171,"url":"https://github.com/rse/componentjs-mvc","last_synced_at":"2025-08-12T15:14:43.737Z","repository":{"id":57204836,"uuid":"65836976","full_name":"rse/componentjs-mvc","owner":"rse","description":"Model-View-Controller Component Roles for ComponentJS","archived":false,"fork":false,"pushed_at":"2018-12-29T12:00:33.000Z","size":56,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-07T00:37:40.916Z","etag":null,"topics":["abstract","class","componentjs","mvc","oop"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-16T16:43:27.000Z","updated_at":"2018-12-29T12:00:31.000Z","dependencies_parsed_at":"2022-09-11T06:51:34.389Z","dependency_job_id":null,"html_url":"https://github.com/rse/componentjs-mvc","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/rse/componentjs-mvc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fcomponentjs-mvc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fcomponentjs-mvc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fcomponentjs-mvc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fcomponentjs-mvc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rse","download_url":"https://codeload.github.com/rse/componentjs-mvc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rse%2Fcomponentjs-mvc/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269688089,"owners_count":24459403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract","class","componentjs","mvc","oop"],"created_at":"2025-01-23T05:47:33.688Z","updated_at":"2025-08-12T15:14:43.713Z","avatar_url":"https://github.com/rse.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\nComponentJS MVC\n===============\n\nModel-View-Controller Component Roles.\n\n\u003cp/\u003e\n\u003cimg src=\"https://nodei.co/npm/componentjs-mvc.png?downloads=true\u0026stars=true\" alt=\"\"/\u003e\n\n\u003cp/\u003e\n\u003cimg src=\"https://david-dm.org/rse/componentjs-mvc.png\" alt=\"\"/\u003e\n\nAbout\n-----\n\n[ComponentJS](https://componentjs.com/) is a generic hierarchical\ncomponent orchestration library. It has no direct notion of any\ncomponent roles, although it was designed with the roles of Ralf S.\nEngelschall's Model-View-Controller/Component-Tree (MVC/CT) pattern\nin mind. ComponentJS MVC is an opinionated companion library to\n[ComponentJS](https://componentjs.com/), providing ECMAScript 6 abstract\nclasses for implementing the classes of ComponentJS backing objects\nby using the distinct Model, View or Controller roles of the MVC/CT\npattern. The abstract classes map the major and essential parts of the\nComponentJS API onto local methods which then provide the ComponentJS\nfunctionality in a way which is slightly adjusted for convenience\nreasons and their distinct usage under MVC/CT. ComponentJS MVC is\nintended to simplify the programming of HTML5 Single-Page-Apps (SPA) in\nan Object-Oriented Programming (OOP) manner.\n\nInstallation\n------------\n\n```shell\n# with the help of the NPM package manager (primary approach)\n$ npm install componentjs-mvc\n\n# with the help of the YARN package manager (alternative approach)\n$ yarn add componentjs-mvc\n\n# with the help of the Bower package manager (obsolete approach)\n$ bower install componentjs-mvc\n```\n\nUsage\n-----\n\n### Main Procedure:\n\n```js\nimport $   from \"jquery\"\n\nimport cs  from \"componentjs\"\nimport          \"componentjs/component.plugin.vue.js\"\n\nimport mvc from \"componentjs-mvc\"\n\nimport SV  from \"./service\"\n\nclass App {\n    static main () {\n        /*  fire up ComponentJS  */\n        cs.bootstrap()\n        cs(\"/\").property(\"sv\", new SV())\n\n        /*  fire up ComponentJS MVC  */\n        mvc.jQuery      = $\n        mvc.ComponentJS = cs\n        mvc.Plugin()\n        mvc.latch(\"mask:vue-options\", ({ id, options }) =\u003e {\n            /*  example: provide id to Vue-I18Next Vue plugin  */\n            options.i18nextNamespace = id\n        })\n        mvc.latch(\"mask:vue-result\", ({ id, mask }) =\u003e {\n            /*  example: integrate Perfect-Scroll-Bar jQuery plugin  */\n            $(\".perfect-scroll-bar\", mask.$el).perfectScrollbar({})\n        })\n    }\n}\n\n```\n\n### Dialog Component:\n\n```js\nimport mvc from \"componentjs-mvc\"\n\nclass View extends mvc.View {\n    ...\n}\nclass Model extends mvc.Model {\n    ...\n}\nclass Controller extends mvc.Controller {\n    ...\n}\n```\n\nApplication Programming Interface (API)\n---------------------------------------\n\n### Globals:\n\n- `import mvc from \"componentjs-mvc\"`:\u003cbr/\u003e\n  Load the ComponentJS-MVC library.\n\n- `mvc.ComponentJS = ...`:\u003cbr/\u003e\n  Configure ComponentJS-MVC to use a particular instance of the mandatory ComponentJS framework.\n  By default ComponentJS-MVC uses the global symbol `ComponentJS`.\n\n- `mvc.jQuery = ...`:\u003cbr/\u003e\n  Configure ComponentJS-MVC to use a particular instance of the optional\n  jQuery library. By default ComponentJS-MVC uses the global symbol\n  `jQuery`. jQuery is necessary only if the `mvc.View::$()` method\n  should be used. jQuery and jQuery-Markup are necessary only if the\n  `mvc.View::mask()` method should be used with neither `template` nor\n  `render` options.\n\n- `mvc.Plugin()`:\u003cbr/\u003e\n  Hook into ComponentJS as an `mvc` plugin to automatically mark\n  dynamically created ComponentJS-MVC-based components with the proper\n  marker for the ComponentJS debugger without having to override the\n  `create()` method and this way cause a `super.create()` burden on the\n  users of the ComponentJS-MVC classes. Call this once in your main\n  procedure if you want proper colors in the ComponentJS debugger for\n  ComponentJS-MVC-based components.\n\n### Hooks:\n\n- `mvc.latch(\"mask:vue-options\", (({ id, options }) =\u003e { ... })`:\u003cbr/\u003e\n  Hook into the `mvc.View::mask()` method just before `mask = ComponentJS::vue(options)`\n  is called internally. Use this to set particular options for VueJS.\n  For instance, use `mvc.latch(\"mask:vue-options\", ({ id, options }) =\u003e { options.i18nextNamespace = id })`\n  to set the I18N namespace when using VueJS and the Vue-I18Next plugin together.\n\n- `mvc.latch(\"mask:vue-result\", (({ id, result }) =\u003e { ... })`:\u003cbr/\u003e\n  Hook into the `mvc.View::mask()` method just after `mask\n  = ComponentJS::vue(options)` is called internally. Use\n  this to post-process the VueJS instance. For instance,\n  use `mvc.latch(\"mask:vue-result\", (({ id, result }) =\u003e {\n  $(\".perfect-scroll-bar\", mask.$el).perfectScrollbar({ ... }) })` to\n  apply the jQuery Perfect-Scrollbar plugin.\n\n- `mvc.latch(\"establish:post-create\", ({ id, comp, obj }) =\u003e { ... })`:\u003cbr/\u003e\n  Hook into the `mvc.Component::establish()` method after each component\n  was created. Use this to post-adjust created components. The `comp`\n  is the created component, `obj` the attached backing object derived from the\n  arguments to `mvc.Component::establish()`.\n\n- `mvc.latch(\"establish:pre-destroy\", ({ id, comp, obj }) =\u003e { ... })`:\u003cbr/\u003e\n  Hook into the `mvc.Component::demolish()` method before each component\n  will be destroyed. Use this to pre-process components. The `comp`\n  is the created component, `obj` the attached backing object derived from the\n  arguments to `mvc.Component::establish()`.\n\n### Classes:\n\n- `class Component extends mvc.Component { ... }`:\u003cbr/\u003e\n  Define an application Component class based on ComponentJS-MVC's Component class\n  (usually not directly used in regular applications, but exposed for completeness reasons).\n\n- `class View extends mvc.View { ... }`:\u003cbr/\u003e\n  Define an application View class based on ComponentJS-MVC's View class.\n  The `mvc.View` class inherits from the `mvc.Component` class.\n\n- `class Model extends mvc.Model { ... }`:\u003cbr/\u003e\n  Define an application Model class based on ComponentJS-MVC's Model class.\n  The `mvc.Model` class inherits from the `mvc.Component` class.\n\n- `class Controller extends mvc.Controller`:\u003cbr/\u003e\n  Define an application Controller class based on ComponentJS-MVC's Controller class.\n  The `mvc.Controller` class inherits from the `mvc.Component` class.\n\n### Methods (Component/View/Model/Controller Classes):\n\n- `mvc.Component::cs(...): ComponentJS`:\u003cbr/\u003e\n  Use the configured ComponentJS by just passing-through execution\n  to ComponentJS. Use this in case you want to directly access the\n  ComponentJS API from within a ComponentJS-MVC component.\n\n- `mvc.Component::establish(anchor?: Component, tree: String, classes: Object|Object[], autoincrease?: Boolean = true, autodecrease?: Boolean = false): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::create()`.\n  It internally basically calls `mvc.ComponentJS(this[, anchor]).create(tree, classes.map((Clz) =\u003e typeof Clz === \"function\" ? new Clz() : Clz))`\n  and remembers the created components by their id for forthcoming use via `mvc.Component::my()`.\n  It also calls `ComponentJS::state_auto_increase(autoincrease)`\n  and `ComponentJS::state_auto_decrease(autodecrease)` on all created components.\n\n- `mvc.Component::demolish(id?: String): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::destroy()`.\n  It either destroys just the specified component (by id) or all\n  components previously created with `mvc.Component::establish()`.\n\n- `mvc.Component::my(id: String): ComponentJS`:\u003cbr/\u003e\n  This fetches (by id) a particular component previously created with `mvc.Component::establish()`.\n\n- `mvc.Component::exists(id: String): ComponentJS`:\u003cbr/\u003e\n  This checks (by id) whether a particular component previously was\n  created with `mvc.Component::establish()` and was still not destroyed\n  with `mvc.Component::demolish()`.\n\n- `mvc.Component::state(...args: any[]): ComponentJS`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::state()`. The\n  `args` positional arguments are just passed-through. The return value\n  is the value of `ComponentJS::state()`.\n\n- `mvc.Component::guard(...args: any[]): ComponentJS`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::guard()`. The\n  `args` positional arguments are just passed-through. The return value\n  is the value of `ComponentJS::guard()`.\n\n- `mvc.Component::await(...args: any[]): ComponentJS`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::await()`. The\n  `args` positional arguments are just passed-through. The return value\n  is the value of `ComponentJS::await()`.\n\n- `mvc.Component::spool(func: Function, options?: Object): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::spool()`. It\n  internally basically calls `mvc.ComponentJS(this).spool({ name:\n  mvc.ComponentJS(this).state(), ctx: this, func: func, ...options })`.\n  The twist of this wrapper is that it automatically uses the component\n  state based spool.\n\n- `mvc.Component::observe(name: String|String[], func: Function, options?: Object): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::observe()`.\n  It internally basically calls `mvc.ComponentJS(this[, \"model\"])\n  .observe({ name, func, spool: mvc.ComponentJS(this).state(), noevent:\n  true, ...options })`. The twists of this wrapper are: it performs\n  automatical spooling, uses no event argument in the `func` callback\n  and automatically steps down to a `model` child if `this` is a\n  `mvc.Controller`. Additionally, instead of a single `name`, it allows\n  you to pass an array of names.\n\n- `mvc.Component::value(...args: any[]): any`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::value()`. It\n  internally basically calls `mvc.ComponentJS(this[, \"model\"])\n  .value(...args)`. The main twist of this wrapper is: it automatically\n  steps down to a `model` child if `this` is a `mvc.Controller`.\n\n- `mvc.Component::touch(...args: any[]): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::touch()`. It\n  internally basically calls `mvc.ComponentJS(this[, \"model\"])\n  .touch(...args)`. The main twist of this wrapper is: it automatically\n  steps down to a `model` child if `this` is a `mvc.Controller`.\n\n- `mvc.Component::subscribe(name: String|String[], func: Function, options?: Object): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::subscribe()`. It\n  internally basically calls `mvc.ComponentJS(this).subscribe({ name,\n  func, spool: mvc.ComponentJS(this).state(), noevent: true, capturing:\n  false, spreading: false, bubbling: true, ...options })`. The twists\n  of this wrapper are: it performs automatical spooling, uses no event\n  argument in the `func` callback, disables capturing and spreading, and\n  enables bubbling. Additionally, instead of a single `name`, it allows\n  you to pass an array of names.\n\n- `mvc.Component::publish(name: String, args: any[], options?: Object): any`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::publish()`. It\n  internally basically calls `mvc.ComponentJS(this).publish({ name,\n  args, directresult: true, capturing: true, spreading: false, bubbling:\n  true, ...options })`. The twists of this wrapper are: enables direct\n  results, enables capturing and bubbling and disables spreading.\n\n- `mvc.Component::register(name: String|String[], func: Function, options?: Object): mvc.Component`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::register()`.\n  It internally basically calls `mvc.ComponentJS(this).register({\n  name, func, spool: mvc.ComponentJS(this).state(), capturing: false,\n  spreading: false, bubbling: true, ...options })`. The twists of this\n  wrapper are: it performs automatical spooling, disables capturing and\n  spreading, and enables bubbling. Additionally, instead of a single\n  `name`, it allows you to pass an array of names.\n\n- `mvc.Component::call(name: String, args: any[], options?: Object): any`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::call()`. It\n  internally basically calls `mvc.ComponentJS(this).call({ name, args,\n  capturing: true, spreading: false, bubbling: true, ...options })`. The\n  twists of this wrapper are: it enables capturing, disabled spreading\n  and enables bubbling.\n\n### Methods (View Class):\n\n- `mvc.View::$(selector: String, baseElement?: DOMElement): jQuery`:\u003cbr/\u003e\n  Use the configured jQuery by just passing-through execution to jQuery.\n  Use this in case you want to directly manipulate the DOM via jQuery\n  from within a View component. Use with caution, as jQuery and VueJS\n  can conflict.\n\n- `mvc.View::mask(id: String, options?: any): VueJS`:\u003cbr/\u003e\n  Create a UI Mask with the help of VueJS. The `id` has to be unique\n  within the UI, although it is not directly used by ComponentJS-MVC\n  itself. It is intended to be passed through to the `mask:vue-options`\n  hook and used there accordingly. The `options` are just passed-through\n  to the `ComponentJS::vue()` method. Hence, this method requires the\n  ComponentJS `vue` plugin to be loaded first.\n\n- `mvc.View::socket(ctx: Object, plug: Function, unplug: Function): Number`:\u003cbr/\u003e\n  `mvc.View::socket(options: { ctx: Object, plug?: Function, unplug?: Function, ... }): Number`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::socket()`. The\n  `ctx`, `plug` and `unplug` positional arguments are just converted\n  to the `options` form of method calling. If the `options` argument\n  has no `spool` field, it is automatically created with the value of\n  `mvc.ComponentJS(this).state()`. The return value is the value of\n  `ComponentJS::socket()`.\n\n- `mvc.View::link(target: Object, socket: String): Number`:\u003cbr/\u003e\n  `mvc.View::link(options: { target: Object, socket: String, ... }): Number`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::link()`. The\n  `target` and `socket` positional arguments are just converted\n  to the `options` form of method calling. If the `options` argument\n  has no `spool` field, it is automatically created with the value of\n  `mvc.ComponentJS(this).state()`. The return value is the value of\n  `ComponentJS::link()`.\n\n- `mvc.View::plug(object: Object): Number`:\u003cbr/\u003e\n  `mvc.View::plug(options: { object: Object, ... }): Number`:\u003cbr/\u003e\n  This is a convenience wrapper around `ComponentJS::plug()`. The\n  `object` positional argument is just converted\n  to the `options` form of method calling. If the `options` argument\n  has no `spool` field, it is automatically created with the value of\n  `mvc.ComponentJS(this).state()`. The return value is the value of\n  `ComponentJS::plug()`.\n\n### Methods (Model Class):\n\n- `mvc.Model::model(spec: Object): Void`:\u003cbr/\u003e\n  This just passes-through `spec` to the `ComponentJS::model()` method.\n\n### Methods (Controller Class):\n\n- `mvc.Controller::sv(): Object`:\u003cbr/\u003e\n  This is a short-hand for `mvc.ComponentJS(this).property(\"sv\")`\n  and simplifys the fetching of the underlying Service API, which\n  beforehand should be placed into a property on the root component via\n  `mvc.ComponentJS(\"/\").property(\"sv\", value)`.\n\nLicense\n-------\n\nCopyright (c) 2016-2018 Ralf S. Engelschall (http://engelschall.com/)\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frse%2Fcomponentjs-mvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frse%2Fcomponentjs-mvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frse%2Fcomponentjs-mvc/lists"}