{"id":17181535,"url":"https://github.com/dimitarchristoff/epik","last_synced_at":"2025-04-13T17:50:52.558Z","repository":{"id":12557180,"uuid":"15227506","full_name":"DimitarChristoff/epik","owner":"DimitarChristoff","description":"epitome 2 for primish and lodash, no depenency on mootools","archived":false,"fork":false,"pushed_at":"2015-11-18T12:25:35.000Z","size":4002,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-23T03:32:41.542Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://dimitarchristoff.github.com/epik","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/DimitarChristoff.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":"2013-12-16T14:13:24.000Z","updated_at":"2016-10-23T09:37:12.000Z","dependencies_parsed_at":"2022-09-05T10:50:50.200Z","dependency_job_id":null,"html_url":"https://github.com/DimitarChristoff/epik","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitarChristoff%2Fepik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitarChristoff%2Fepik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitarChristoff%2Fepik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DimitarChristoff%2Fepik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DimitarChristoff","download_url":"https://codeload.github.com/DimitarChristoff/epik/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248758131,"owners_count":21156956,"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","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":[],"created_at":"2024-10-15T00:34:35.935Z","updated_at":"2025-04-13T17:50:52.536Z","avatar_url":"https://github.com/DimitarChristoff.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"epik [![NPM version](https://badge.fury.io/js/epik.png)](http://badge.fury.io/js/epik)\n====\n\nepik is [Epitome](http://epitome-mvc.github.io/Epitome/) ver 2 for `primish`, `lodash` and `jquery/zepto`, no depenency on MooTools.\n\n\u003e Warning: this is a fully functional experiment. If you like primish, MooTools and Epitome, feel free to use or to contribute\n\nepik is a small, modular and extensible MVC framework for modern web development, built in the spirit of AMD and bower components. It will also work with global exports (w/o a dependency loader) and it works under node.js. epik offers 90% of the functionality of Backbone but allows you to develop in the style of MooTools classes via [primish](http://dimitarchristoff.github.io/primish/). The views are either powered by jQuery or via a built-in [rivets.js](http://www.rivetsjs.com/) adapter for bi-directional binding in the style of AngularJS.\n\n- __Q: Why would you use it?__ It allows you to quickly prototype and develop code that runs in the browser or in node.js, sharing components between client and server. It also makes it easy to work with for any ex MooTools developers who are being forced to use jquery in their work.\n\n- __Q: Should I use it?__ Whereas epik is fully functional, tested and powerful, it has literally no adoption in the wild, therefore no community help. For the time being, only use it if you know what you are doing.\n\n[![Build Status](https://api.travis-ci.org/DimitarChristoff/epik.png)](http://travis-ci.org/DimitarChristoff/epik)\n\n## Getting started\n\nTo install epik in your project, you have several routes.\n\n### bower\n```sh\n$ bower install epik --save\n```\n\nA bower install will only bring down the following files:\n\n - `lib/index.js`\n - `lib/model.js`\n - `lib/model-sync.js`\n - `lib/collection.js`\n - `lib/collection-sync.js`\n - `lib/agent.js`\n - `lib/router.js`\n - `lib/storage.js`\n - `lib/plugins/rivets-adapter.js`\n - `lib/epik-min.js`\n\n### script tags\n\nYou can grab the minified concatenated version:\n\n\u003ca class=\"btn btn-large btn-primary\" rel=\"download\" target=\"_blank\" href=\"https://rawgithub.com/DimitarChristoff/epik/master/lib/epik-min.js\"\u003eepik-min.js (27.5k)\u003c/a\u003e (pointing to master branch)\n\n\n`epik` uses the following packages as dependencies, not part of the build:\n\n - lodash (utils)\n - primish (classes)\n - jquery (views)\n - rivets.js (views)\n\nAdditionally, `slicker`, MooTools Slick parser for the web, is bundled in the concatenated minified files but if you use it in development mode and reference all the files locally, you'd need to resolve it as well. Should be done automatically if you use bower/AMD, see below.\n\nMake sure that the dependencies listed above - `primish`, `lodash` and view helpers `jquery` and `rivets.js`, if applicable, are loaded beforehand and use the global object `epik` to reference components.\n\n### node.js\n\n```sh\n$ npm install epik --save\n```\n\nWhen using it under node.js, you need to reference relative paths for sub components. For example:\n\n```javascript\nvar epik = require('epik'),\n\tmodel = require('epik/lib/model');\n```\n\n### AMD configuration\n\nYou can use epik in a number of ways.\n\nIn development, you can let requirejs fetch all dependencies as needed. A typical require.config looks like this:\n\n```javascript\nrequire.config({\n\tpaths: {\n\t\t\tepik: '../bower_components/epik/lib',\n\t\t\t'rivets-adapter': '../bower_components/epik/lib/plugins/rivets-adapter',\n\t\t\tprimish: '../bower_components/primish',\n\t\t\tlodash: '../bower_components/lodash/dist/lodash',\n\t\t\tslicker: '../bower_components/slicker/index',\n\t\t\trivets: '../bower_components/rivets/dist/rivets',\n\t\t\tjquery: '../bower_components/jquery/jquery'\n\t\t}\n\t});\n});\n```\n\nA sample `requirejs-config.js` can be seen at this [gist](https://gist.github.com/DimitarChristoff/e2eafaa605e8d8f19b11). \n\nThe above is applicable after a `bower install epik --save` and will dynamically load any components as needed.\nObviously, you may have a different config for `jquery`, `lodash` and `rivets` so reflect them as needed - epik will require\nthem via the root level ids of `jquery`, `lodash` and `rivets` respectively.\n\nIf you prefer, you can use the builds of epik instead. There are two builds shipped - a minimum one, which includes only\nthe epik files (and `slicker`) and a full one, which includes ALL dependencies, `lodash`, `rivets` and `jquery` into the\nbuild.\n\nThere are module ids set so you can use the RequireJS 2.1.9 feature [bundles](http://requirejs.org/docs/api.html#config-bundles) and\ndefine where to find the resolved modules.\n\nAn example config using the minified built epik would look like this:\n```javascript\nrequire.config({\n\tpaths: {\n\t\tepik: '../bower_components/epik/lib',\n\t\tprimish: '../bower_components/primish',\n\t\tlodash: '../bower_components/lodash/dist/lodash',\n\t\trivets: '../bower_components/rivets/dist/rivets',\n\t\tjquery: '../bower_components/jquery/jquery'\n\t},\n\tbundles: {\n\t\t'epik/epik-min': [\n\t\t\t'epik/index',\n\t\t\t'epik/model',\n\t\t\t'epik/model-sync',\n\t\t\t'epik/collection',\n\t\t\t'epik/collection-sync',\n\t\t\t'epik/agent',\n\t\t\t'epik/storage',\n\t\t\t'epik/router',\n\t\t\t'epik/view',\n\t\t\t'epik/plugins/rivets-adapter',\n\t\t\t'slicker'\n\t\t]\n\t}\n});\n```\n\nOnce that is setup, requests for `epik/model` on an empty require module factory will get the minified built version and\nprime the factory against the module IDs defined above. You should only see a single HTTP request in your console for\n`epik-min.js`. Notice `slicker` is bundled already and the rivets adapter is with the id of `epik/plugins/rivets-adapter`.\n\nUsage in both cases remains the same.\n```javascript\nrequire.config({ ... }});\n\ndefine(function(require){\n\n\tvar primish = require('primish/primish'),\n\t\tModel = require('epik/model-sync');\n\n\tvar User = primish({\n\t\textend: Model\n\t});\n\n\t// ...\n});\n```\n\nIf you use the FULL build from `dist/build/epik-full-min.js`, you would also have to add to the bundles config to let\nrequirejs know it will resolve rivets.js, jquery, lodash and primish as well:\n\n```javascript\nrequire.config({\n\tpaths: {\n\t\tepik: '../bower_components/epik/lib',\n\t\tprimish: '../bower_components/primish',\n\t\tlodash: '../bower_components/lodash/dist/lodash',\n\t\trivets: '../bower_components/rivets/dist/rivets',\n\t\tjquery: '../bower_components/jquery/jquery'\n\t},\n\tbundles: {\n\t\t'epik/epik-min': [\n\t\t\t'epik/index',\n\t\t\t'epik/model',\n\t\t\t'epik/model-sync',\n\t\t\t'epik/collection',\n\t\t\t'epik/collection-sync',\n\t\t\t'epik/agent',\n\t\t\t'epik/storage',\n\t\t\t'epik/router',\n\t\t\t'epik/view',\n\t\t\t'epik/plugins/rivets-adapter',\n\t\t\t'slicker',\n\t\t\t'jquery',\n\t\t\t'lodash',\n\t\t\t'rivets',\n\t\t\t'primish/primish',\n\t\t\t'primish/emitter',\n\t\t\t'primish/options'\n\t\t]\n\t}\n});\n```\n\nKeep in mind that the strings passed to the bundles config are module IDs, not expanded paths.\n\n## Overview\n\nThe framework has been written to use [primish](https://github.com/DimitarChristoff/primish) classes so usage implies\nsome familiarity with how that works - or at the very least, knowledge of either MooTools Class or similar from\nprototype.js or DOJO.\n\nThe basic premise is, `epik` itself returns `primish` in the same namespace (or AMD module). A typical Class looks like\nthis:\n\n```javascript\n// assume a non-AMD environment\nvar MyView = epik.primish({\n\t// set super\n\textend: epik.view,\n\t// local methods and overrides\n\t// ..\n\trender: function(){\n\t\tthis.$element.html(this.model.toJSON());\n\t}\n});\n\nvar instance = new MyView({\n\telement: '#header',\n\ttemplate: 'some html',\n\tmodel: modelInstance\n});\n```\nYou can use primish to create your own controllers or to extend / mixin the existing ones that epik provides.\n\n## Model\n\nThe epik Model implementation at its core is a [primish](https://github.com/DimitarChristoff/primish) class with custom data accessors that fires events. You can extend models or implement objects or other classes into your definitions.\n\nThe Model can fire the following events:\n\n* `ready` - when instantiated\n* `change` - when any properties have changed\n* `change:key` - when a particular property `key` has changed\n* `empty` - when a model has been emptied of all properties\n* `destroy` - when a model has been `destroyed` and all data removed.\n* `error` - when a model validator fails on a property set.\n* `error:key` - when a particular key validation error has occurred\n\nThe following methods are official API on all Model Classes:\n\n### constructor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} obj`, `{Object} options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe `obj` sets the internal data hash to a new derefrenced object. Special accessor properties, as defined in the `epik.model.prototype.properties`, will run first and be applicable. See [properties](#model/model-properties) for more info.\n\nThe `options` object is a `setOptions` override and is being merged with the `epik.model.prototype.options` when a new model is created. It typically contains various event handlers in the form of:\n\n```ace\nrequire(['epik/index', 'epik/model'], function(epik, Model){\n\n\tvar Person = epik.primish('person', {\n\t\textend: Model,\n\t\tdefaults: {\n\t\t\tsex: 'male',\n\t\t\ttitle: 'Mr.',\n\t\t\tage: 0\n\t\t}\n\t});\n\n\tvar bob = new Person({\n\t\tname: 'Bob',\n\t\tage: 30\n\t});\n\n\tconsole.log(bob.toJSON());\n\tconsole.log(bob._id); // 'person'\n});\n```\n\n### set\n---\n\u003cdiv class=\"alert\" markdown=\"1\"\u003e\n\u003cp\u003e\n_Expects arguments: mixed: `{String} key`, `{Mixed} value` - pair - or: `{Object} obj`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events:_\n\n\u003cul\u003e\n \u003cli\u003e `change: function(changedProperties) {}`\u003c/li\u003e\n \u003cli\u003e `change:key: function(valueForKey) {}`\u003c/li\u003e\n \u003cli\u003e `error: function(objectFailedValidation) {}`\u003c/li\u003e\n \u003cli\u003e `error:key: function(objectFailedValidation) {}`\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/p\u003e\n\u003c/div\u003e\n\nAllows changing of any individual model key or a set of key/value pairs, encapsulated in an object. Will fire a single `change` event with all the changed properties as well as a specific `change:key` event that passes just the value of the key as argument.\n\nFor typing of value, you can store anything at all (Primitives, Objects, Functions). Keep in mind that, when it comes to serialising the Model and sending it to the server, only Primitive types or ones with a sensible `toString()` implementation will make sense.\n\n### get\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments mixed: `{String} key` or `{Array} keys`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{mixed|Object}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns known values within the model for either a single key or an array of keys. For an array of keys, it will return an object with `key` : `value` mapping. Properties gotten are not implicitly de-refrenced so careful if you have stored an object - modifying the value of the `get` will modify your model as well.\n\nThe following example illustrates why it's a bad idea to store deep model properties. Alternatively, you can use `instance.toJSON()` and reference and modify properties off of that without them making it back into the model.\n\n```ace\nrequire(['epik/index', 'epik/model'], function(epik, Model){\n\n\tvar Person = epik.primish('person', {\n\t\textend: Model,\n\t\tdefaults: {\n\t\t\tsex: 'male',\n\t\t\ttitle: 'Mr.',\n\t\t\tage: 0\n\t\t}\n\t});\n\n\tvar bob = new Person({\n\t\ta: 'a',\n\t\tb: 'b',\n\t\tlocation: {\n\t\t\tcountry: 'UK',\n\t\t\tcity: 'London'\n\t\t}\n\t});\n\n\tvar location = bob.get('location');\n\tconsole.log(location.city); // London\n\tlocation.city = 'Manchester';\n\tconsole.log(bob.get('location').city); // Manchester. oh no!\n\n\t// get around dereferencing\n\tlocation = epik._.clone(bob.get('location'));\n\tlocation.city = 'London';\n\tconsole.log(bob.get('location').city); // Still Manchester.\n\n\t// multiple property getters\n\tconsole.log(bob.get(['a','b']));\n});\n```\n\n### toJSON\n------\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{Object} data`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns a de-referenced Object, containing all the known model keys and values.\n\n### unset\n-----\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: mixed: `{String} key1` .. `{String} keyN` or `{Array} keys`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves keys from model, either a single one or an array of multiple keys. Should fire a change event for every property removed as well as a `change`. If a property does not exist in the model, no change event will fire for it.\n\n### empty\n-----\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nEmpties the model of all data and fires a single change event with all keys as well as individual `change:key` events.\n\n### destroy\n-------\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `destroy`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nEmpties the model. No change event. Event is observed by Collections the model is a member of, where it triggers a `remove()`\n\n### validate\n-------\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: {String} key, {*} value_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{Boolean} validates`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nInternal method that gets run whenever a property is being set. Checks to see if there is a validator for the `key`, is so, returns the result of the validator function, else, assumes it's allowed and returns `true`\n\n### Model properties*\n\nThere are several additional properties each model instance will have.\n\n#### _attributes: {Object}\n-------\nThe attributes object is __public__ (exposed to manipulation on the instance) and it holds the hash data for the model, based upon keys. It is de-referenced from the constructor object used when creating a model but should not be read directly (normally). Exported by `model.toJSON()`. Avoid changing this directly as it won't fire any change events at all.\n\n#### _collections: {Array}\n-------\nAn array that contains references to all instances of epik.collection that the model is currently a member of. Useful for iteration as well as utilised by collections that subscribe to events for models.\n\n#### options: {Object}\n-------\nA default options set, which can be on the prototype of the Model constructor.\n\n#### defaults: {Object|Function}\n-------\nAn object with default Model Attributes to use when instantiating. Merged with Model object when populating model data via the constructor. Also accepts a function, which should return an object, performed in the constructor.\n\n#### propertiesChanged: {Array}\n-------\nAn array of all property keys that reflect the last `change` event. Available on all instances.\n\n#### validationFailed: {Array}\n-------\nAn array of all error Objects with info on all validation failed properties after a `set`. Available on all instances.\n\n#### properties: {Object}\n-------\nA collection of custom accessors that override default `model.get` and `model.set` methods. For example:\n\n```javascript\nproperties: {\n\tdob: {\n\t\tget: function() {\n\t\t\t// scope is model\n\t\t\treturn new Date(this._attributes.dob);\n\t\t},\n\t\tset: function(value) {\n\t\t\t// return a value to be set\n\t\t\treturn value instanceof Date ? +value : value;\n\t\t}\n\t},\n\tid: {\n\t\tget: function(){\n\t\t\t// returns a property from instance instead of _attributes\n\t\t\treturn this.id;\n\t\t},\n\t\tset: function(id){\n\t\t\tthis.id = id;\n\t\t\t// may want to fire events manually here.\n\t\t}\n\t},\n\tprice: {\n\t\tset: function(value){\n\t\t\treturn this.formatCurrency(value);\n\t\t}\n\t}\n}\n```\nIn the examples above, any calls to `model.set('dob', new Date(1985, 5, 15))` and `model.get('dob')` are handled by custom functions as we want our model to deal with unix timestamps only but return Date instances. This is a pattern that allows you to use getters and setters for properties that are handled differently than normal ones. If the `set` function returns a value, it will use the normal `set` chain and act as a formatter/pre-processor, firing events etc. You don't have to use this and can do as in the `id` example, where the value is simply redirected elsewhere.\n\nAvoid setting them on prototypes that you extend from, better to have them on the instance from the constructor or another method as they are not de-referenced and are not being merged. If you need to extend them and keep the default id getter, you need to merge with `model.prototype.properties` in your new model definitions. This may change in future versions.\n\n```javascript\nvar Person = primish({\n\tproperties: _.merge({\n\t\tfoo: {\n\t\t\tget: function(){},\n\t\t\tset: function(){}\n\t\t}\n\t}, epik.model.prototype.properties);\n});\n```\n\n### Model validators*\n\nYou can also include basic validators into your model. Validators are an object on the Model prototype that maps any expected key to a function that will return `true` if the validation passes or a `string` error message or `false` on failure.\n\nHere is an example:\n```ace\nrequire(['epik/index', 'epik/model'], function(epik, Model){\n\n\tvar Person = epik.primish('person', {\n\t\textend: Model,\n\t\tvalidators: {\n\t\t\temail: function(value) {\n\t\t\t\treturn (/(.+)@(.+){2,}\\.(.+){2,}/).test(value) ? true : 'This looks like an invalid email address';\n\t\t\t}\n\t\t}\n\t});\n\n\tvar userInstance = new Person({}, {\n\t\tonError: function(allErrors) {\n\t\t\tconsole.log('The following fields were rejected', allErrors);\n\t\t},\n\t\t'onError:email': function(errorObj) {\n\t\t\t// can have a custom message, action or whatever.\n\t\t\tconsole.log('Email rejected', errorObj.error);\n\t\t}\n\t});\n\n\tuserInstance.set('email', 'this will fail!');\n\n});\n```\nThe `error` event is observed by collections and views and fires on all view and collection instances.\n\n\n## Model Sync\n\nThis is an example implementation of RESTful module that extends the base epik.model class and adds the ability to read, update and delete models with remote server. In terms of implementation, there are subtle differences. The API and methods are as per the normal [Model](#model), unless outlined below:\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} model`, `{Object} options`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nmodel-sync extends the normal model by adding some extra properties, namely `id` and a `urlRoot` either as a property of the model or as an options property, which allow you to sync it. The constructor function first calls the parent model constructor and then sets up the XHR instance and methods via a custom implementation of [agent](https://github.com/kamicane/agent), which supports XHR2. `agent.js` is a local file that does not need to be included separately due to certain changes around CORS headers and primish that are not available upstream.\n\n\u003cdiv class=\"alert\"\u003e\n`options.headers` {Object} is a way to pass headers to the Agent instance, such as the `content-type` to `application/json` (by default), etc.\n \u003c/div\u003e\n\n### sync\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\nExpects optional arguments: `{String} method`, `{Object} model`, `{Function} callback`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `success|failure`: `function(responseObj) {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSync acts as a proxy/interface to the XHR instance in the model `this.request` A method can be one of the following:\n\u003e get, post, create, read, delete, update\n\nIf no method is supplied, a `read` is performed.\n\nThe second argument `model` is optional and should be a simple object. If it is not supplied, the default `model.toJSON()` is used instead.\n\nIf a callback is supplied, it will be called when done - although it will still raise the `success` or `failure` events\n\nAs a whole, you should probably NOT use the sync directly but elect to use the API methods for each specific request task.\n\n__WARNING:__ epik is a REST framework. Please make sure you are returning a valid JSON string or 204 (no content) after all requests -\notherwise, the save events may not fire. Additionally, try to ensure `application/json` content type of your response so that the response is converted to an Object when passed back. Failing to do so will return it raw as plain text or whatever content type you have supplied.\n\n### postProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `{Object} response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you pass in your definition of Models for doing any post-processing of data `returned` by sync from the server. For example:\n\n```javascript\npostProcessor: function(response) {\n\t// data comes back with decoration. split them first.\n\tthis.meta = response.meta;\n\treturn response.data;\n}\n```\n\n### save\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects optional arguments: `{String} key`, `{String} value` or `{Object} keyValues`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `save`, `success|failure`, also either `create` or `update`, dependent on if the model is new_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe save should send the contents of the model to the server for storage. If it is a model that has not been saved before or fetched from the server, it will do so via `create()`, else, it will use `update()` instead.\n\nIf the optional `key` =\u003e `value` pair is passed, it will set them on the model and then save the updated model.\n\n### preProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `{Object} response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you can add to your definition of Models for doing any pre-processing of data before using `CREATE` or `UPDATE` via, `.save` when syncing to a server. For example:\n\n```javascript\npreProcessor: function(data) {\n\t// remove local property 'meta' which the server does not like.\n\tdelete data.meta;\n\treturn data;\n}\n```\n\n### fetch\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `fetch`, `read`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIt will request the server to return the model object for the current id via a `.read()`. It will also change the status of the model (`model.isNewModel`) to false, meaning `.save()` will never use `.create()`. The fetch event will fire once the response object has been returned. The response object is then merged with the current model via a `.set`, it won't empty your data. To do so, you need to issue a `.empty()` first.\n\n### CRUD\n\nAs a side note, the following methods are exported on the model instance:\n\n- `create` - maps to POST\n- `read` - maps to GET\n- `update` - maps to POST\n- `delete_` - maps to DELETE (note that due to IE8, use of `delete` and dot notation throws so it has been renamed)\n\n\n## Collection\n\nCollections are in essence, an Array-like Type with Models as members. By passing a model prototype, adding and removing of models works either based with simple JSPO data has or an actual Model instance. Collections observe and bubble all events that all of its model members emit, firing them on the collection instance. It also allows for filtering, mapping, sorting and many sugar methods, copied from the Array.prototype and applied on the Model.\n\nUnlike Arrays, collections here also allow a powerful search/filter that can return a subset {Array} of Models from the collection that match CSS-like selectors for model attributes\n\nInstances of collection should have a `._id` property of collection, unless you override that.\n\n### constructor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Array|Object} models|objects` (or a single model /object), `{Object} options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe constructor method will accept a large variety of arguments. You can pass on either an Array of Models or an Array of Objects or a single Model or a single Object. You can also pass an empty Array and populate it later. Typical Collection prototype definition looks something like this:\n```javascript\nvar userModel = primish({extend: epik.model}),\n\tusersCollection = primish({\n\t\textend: epik.collection,\n\t\tmodel: userModel // or epik.model by default\n\t});\n\nvar users = new usersCollection([{\n\tid: 'bob'\n}], {\n\tonChange: function(model, props) {\n\t\tconsole.log('model change', model, props);\n\t},\n\tonReady: function() {\n\t\tconsole.log('the collection is ready');\n\t}\n});\n```\nFor reference purposes, each Model that enters a collection needs to have a `cid` - collection id. If the Model has an `id`, that is preferred. Otherwise, a `cid` will be generated. If the Model gets an `id` later on, the `cid` will not be changed.\n\n\u003cdiv class=\"alert alert-info\"\u003e\n\u003cp\u003e\n_Please note that Collections **observe** and bubble **all** model events. For instance, if a Model fires `change`, the Collection instance will fire `onChange`, passing the model as `arguments[0]` and then keeping the rest of the arguments in their original order. For the purposes of implementing this, a decorated local copy of each Model's `.fireEvent` method is created instead of the one from Class.Event prototype. Once a Model stops being a member of collections, the original `fireEvent` is restored by deleting the local method on the Model instance._\n\u003c/p\u003e\n\u003c/div\u003e\n\n### set\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Array|Object} model(s)` , `{Boolean} quiet`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `set: function() {}`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSets models into the collection 'sugar'. Accepts a single model or an array of models to add, passing through to `.add` and also firing a `set` event when done. Previously `.reset` in Epitome.\n\n### add\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object|Model} model` , `{Boolean} replace`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `model`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `add: function(model, cid) {}`, `reset`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nPreviously `addModel` in Epitome. Adding a Model to a Collection should always go through this method. It either appends the Model instance to the internal `_models` Array or it creates a new Model and then appends it. It also starts observing the Model's events and emitting them to the Collection instance with an additional argument passed `Model`. So, if you add a Model stored in `bob` and then do `bob.trigger('hai', 'there')`, the collection will also fire an event like this: `this.trigger('hai', [bob, 'there']); Adding a Model also increases the `Collection.length` property.\n\nWhen a model is added, the collection uses `listenTo()` to subscribe to all methods from the model and bubble them locally. Previously, this used to overload the `fireEvent` method in Epitome's Models but it no longer does.\n\nIncrements the `Collection.length` property (if not replacing existing models).\n\n### remove\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Mixed} model(s)`, `{Boolean} quiet`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `remove: function(model, cid) {}`, `reset`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThis method allows you to remove a single model or an array of models from the collection in the same call. For each removed model, a `remove` Event will fire (if `quiet` is not true). When removing of all Models is done, the collection will also fire a `reset` event, allowing you to re-render your views etc.\n\nIn addition to removing the Model from the Collection, it removes the reference to the Collection in the Model's `_collections` Array and stops observing the Model's events.\n\nDecrements the `Collection.length` property.\n\n### at\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Number} index`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `undefined`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns a particular model by reference to current oder, eg. `collection.at(3)` will return `collection._models[3]`. Index is 0-based.\n\n### getModelById\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{String} id`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nPerforms a search in the collection by the Model's `id` via the standard model `getter`. Returns found Model instance or `null` if no match is found.\n\n### getModelByCID\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{String} cid`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelInstance` or `null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nPerforms a search in the collection by the `cid` property (Collection ID). Returns found Model instance or `null` if no match is found.\n\n### toJSON\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `modelsData`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReturns an array of the results of the `.toJSON()` method called on all Models instances in the collection. Resulting array is de-referenced from both the collection and models instances.\n\n### empty\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Boolean} quiet`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `remove`, `set`, `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nApplies `this.remove` to all Models of the collection. Fires `empty` when done - though before that, a `remove` and `reset` will fire unless `quiet` is set as `true`, see [remove](#collection/remove)\n\n### sort\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: {String|Function} how_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `sort`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nSorting is quite flexible. It works a lot like `Array.prototype.sort`. By default, you can sort based upon strings that represent keys in the Models. You can also stack up secondary, trinary etc sort keys in case the previous keys are equal. For example:\n```javascript\nusers.sort('name');\n// descending order pseduo\nusers.sort('name:desc');\n// by type and then birthdate in reverse order (oldest first)\nusers.sort('type,birthdate:desc');\n```\nSorting also allows you to pass a function you define yourself as per the [Array.prototype.sort](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) interface. When done, it will fire a `sort` event.\n\n### reverse\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `sort`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nReverses sort the order of Models in the collection. Fires a `sort` event, not `reverse`\n\n### find\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: {String} expression_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{Array} MatchingModelObjects`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThis is an experimental API and is subject to change without notice. `Collection.find` is currently powered by the MooTools `Slick.parse` engine. This means you can\n search through your Collection for Models by attributes and `#ids` like you would search in a CSS selector.\n\nFor example:\n```ace\nrequire([\n\t'epik/collection'\n], function(Collection) {\n\n\tvar collection = new Collection([{\n\t\tname: 'Bob',\n\t\tid: 2\n\t}, {\n\t\tname: 'Angry Bob',\n\t\tid: 3\n\t}]);\n\n\tconsole.log(collection.find('[name]')); // where name is defined.\n\tconsole.log(collection.find('[name=Bob]')); // where name is exactly Bob.\n\tconsole.log(collection.find('[name*=Bob]')); // where name contains Bob.\n\tconsole.log(collection.find('[name$=Bob]')); // where name ends on Bob.\n\tconsole.log(collection.find('[name^=Bob]')); // where name starts with Bob.\n\tconsole.log(collection.find('[name=Bob],[name^=Angry]')); // name Bob OR starting with Angry.\n\tconsole.log(collection.find('[name=Bob][id]')); // name Bob AND to have an id\n\tconsole.log(collection.find('#2[name=Bob],#3')); // (name Bob AND id==2) OR id==3\n\tconsole.log(collection.find('[name=Bob][id=2]')); // name Bob AND id==2\n});\n```\n\nSupported operators are `=` (equals), `!=` (not equal), `*=` (contains), `$=` (ends on), `^=` (starts with). Currently, you cannot reverse a condition by adding `!` or `not:` - in fact, pseudos are not supported yet. Find is just sugar and for more complicated stuff, you can either extend it or use `filter` instead.\n\nA sugar 'feature' has been added that allows you to quickly select deeper object properties by treating any parent keys as tags. For instance:\n\n```ace\nrequire([\n\t'epik/collection'\n], function(Collection) {\n\n\tvar collection = new Collection([{\n\t\tname: 'Bob',\n\t\tpermissions: {\n\t\t\tedit: 'true'\n\t\t}\n\t}, {\n\t\tname: 'Angry Bob',\n\t\tpermissions: {\n\t\t\tedit: 'false'\n\t\t}\n\t}]);\n\n\tconsole.log(collection.find('permissions[edit]')); // all where there is an edit property\n\tconsole.log(collection.find('permissions[edit=true]')); // all where there edit is true\n});\n```\n\nHowever, this is more of a convenience than convention. Since it does not do type checking, it is difficult to pass what type of a value you are after in a string. In the example above, `edit` needs to be exactly the string `true`. For complex selectors and non-string data, you should use your own `.filter` methods.\n\nIt also won't allow you to do complex CSS-like selections as you cannot combine 'tag' with properties. This means you cannot do `permissions[edit][name=Bob]` as the search context changes to the permissions property. This kind of structure is possibly an anti-pattern anyway, try to keep your models flat and avoid nested objects where possible.\n\n### findOne\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: {String} expression_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{Model} First matching Model instance or null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nUseful for getting a single Model via the `.find`, this method will return the first matched Model or null if none found.\n\n```javascript\nvar bob = collection.findOne('[name=bob]');\n// if found, set\nbob \u0026\u0026 bob.set('name','Robert');\n```\n\n### Array helpers\n\nThe following Array methods are also available directly on the Collection instances:\n\n* forEach\n* each (alias for forEach)\n* invoke\n* filter\n* map\n* some\n* indexOf\n* contains\n* getRandom\n* getLast\n\n### where\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: {Object} attributes_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `{Model} First matching Model instance or null`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nUseful for getting a single Model via the lodash `_.find` API, this method will return the first matched Model that has\nthe exact same properties as the attributes map passed in or null/undefined if none found. CASE SENSITIVE.\n\n```javascript\nvar bob = collection.where({name: 'bob'});\n// if found, set\nbob \u0026\u0026 bob.set('name','Robert');\n```\n\n### Collection properties*\n\n#### _models\n---\nEach Collection instance has an Array property called `_models` that contains all referenced Model instances. Even though it is not a real private property, it is recommended you do not alter it from outside of the API.\n\n#### length\n---\nTries to always reference the length of `_models`, unless you have directly modified `_models` without using the API.\n\n#### model\n---\nEach Collection prototype has that property that references a Model prototype constructor. When data is being received in raw format (so, simple Objects), Models are being created by instantiating the stored constructor object in `this.model`.\n\n#### id\n---\nDue to serialisation and the ability to use storage to retrieve a collection later, each collection has an id, derived either from the options object or generated at random.\n\n## Collection Sync\n\nThe Sync collection is just a tiny layer on top of the normal [collection](#collection). It `extends` the default Collection class and adds an agent instance that can retrieve an array of Model data from a server and add / update the Collection after.\n\n### constructor (initialize)\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Array|Object} models|objects` (or a single model /object), `{Object} options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIn terms of differences with the original prototype, the `options`, needs just one extra key: `urlRoot`, which should contain the absolute or relative URL to the end-point that can return the Model data.\n\n### fetch\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects optional arguments: `{Boolean} refresh`, `{Object} queryParams`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `this`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `fetch`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWhen called, it will asynchronously try to go and fetch Model data. When data arrives, Models are reconciled with the Models in the collection already by `id`. If they exist already, a `set()` is called that will merge new data into the Model instance and fire `change` events as appropriate. If the optional `refresh` argument is set to true, the current collection will be emptied first via [empty](#epitomecollection/empty).\n\nReturns the instance 'now' but because it is async, applying anything to the collection before the `fetch` event has fired may have unexpected results.\n\nThe `queryParams` object, which is also optional, allows you to pass on any `GET` arguments to the `baseUrl`. If your default endpoint looks like this:\n\n`/comments/2/` and you call `collection.fetch(false, {page: 2})`, it will actually get `/comments/2/?page=2`.\n\nKeep in mind that agent will serialize the response as per the content type, just like in Model Sync. If it's `application/Json`, the decoder will kick in and set the response into the instance.\n\n### postProcessor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Array|Mixed} response`_\n\u003c/p\u003e\n\u003cp\u003e\n_Expected return: `{Array} response`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA method that you can extend in your definition of Epitome.Collection.Sync for doing any pre-processing of data returned by sync from the server. For example:\n\n```javascript\nvar Users = primish({\n\textend: epik.collection,\n\tmodel: UserModel,\n\tpostProcessor: function(response){\n\t\t// data comes back with decoration. split them first.\n\t\t// { meta: { something: 'here' }, models: [] }\n\t\tthis.meta = response.meta;\n\t\treturn response.models;\n\t}\n});\n```\n\n## View\n\nThe view is very un-assuming. It can work with either DOM library (jquery, jquery-lite, zepto) and a templating\nengine like handlebars or lodash.template. It can also work with a template binding engine like rivets.js. A combination\nof both is also possible.\n\n### constructor\n\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nThe default view is a pretty loose binding around a HTMLElement, it does not try to do much by default. It essentially binds an element to either a Model or a Collection, listening and propagating events that they fire in order to be able to react to them. It has glue to pass DOM events delegating into the element to the instance as events or by calling methods on the instance, when possible.\n\nThe expectation is that a `render` method will be defined that uses the data to output it in the browser. How the render can be called is up to you, eg. on `change` or `reset` events.\n\nA single argument in the shape of an `options` Object is passed to the constructor of the View. It is expected to have special 'mutator'-like properties and key properties that it stores for future use.\n\nSignificant keys to the options passed in are:\n\n* `element` - a String id or an element to bind events to and reference\n* `model` - optional Model instance structure to bind to. Exchangeable with `collection`\n* `collection` - optional Collection instance to bind to. Exchangeable with `model`\n* `template` - a String of raw HTML that defines the raw template to use in output.\n* `events` - an Object with MooTools style event bindings to apply to the `element`, delegated or not. values are implied event handlers on the instance\n* `onEventHandlers` - code that reacts to various events that the instance fires.\n\nEpik views do not support the `tag` options of Backbone, you need to figure the elements on your own.\n\n\u003e By default, if you have a method called `attachEvents`, it will automatically get called from the constructor function. If\nyou are extending `view`, then `this.parent('constructor', options);` will have the same effect.\n\n```ace\nrequire([\n\t'epik/index',\n\t'epik/view',\n\t'epik/model'\n], function(epik, View, Model) {\n\t'use strict';\n\n\tvar primish = epik.primish,\n\t\ttpl = 'I am template \u003ca href=\"#\" class=\"task-rename\"\u003e\u003c%=name%\u003e \u003c%=status%\u003e\u003c/a\u003e\u003cbr/\u003e\u003cbutton class=\"done\"\u003ecompleted\u003c/button\u003e';\n\n\tvar testView = primish({\n\n\t\textend: View,\n\n\t\toptions: {\n\t\t\tevents: {\n\t\t\t\t'click a.task-rename': 'renameTask',\n\t\t\t\t'click button.done': 'reset'\n\t\t\t}\n\t\t},\n\n\t\trender: function(){\n\t\t\tthis.empty();\n\t\t\tthis.$element.html(this.template(this.model.toJSON()));\n\t\t\tthis.parent('render');\n\t\t\treturn this;\n\t\t},\n\n\t\treset: function(){\n\t\t\tthis.model.set('status', 'done');\n\t\t\tthis.render();\n\t\t},\n\n\t\trenameTask: function(event){\n\t\t\tevent \u0026\u0026 event.preventDefault \u0026\u0026 event.preventDefault();\n\t\t\tthis.model.set('name', 'Changed name');\n\t\t}\n\t});\n\n\n\tvar testInstance = new testView({\n\n\t\tmodel: new Model({name: 'View fun', status: 'pending'}),\n\n\t\telement: '#main',\n\n\t\ttemplate: tpl,\n\n\t\tonReady: function(){\n\t\t\tthis.render();\n\t\t},\n\n\t\t'onModel:change': function(){\n\t\t\tthis.model.set('name', new Date().getTime());\n\t\t\tthis.render();\n\t\t}\n\t});\n});\n```\n\n### render\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: unknown_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `render`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nIt is essential that this method is defined in your View prototype declaration. It does not assume to do anything by default, you _need_ to define how the output takes place and how your data is being used. For convenience, it has access to either `this.model` or `this.collection` as the source of data that can be be passed to the [template](#view/template) method. It is expected that at the bottom of your definition, `this.parent('render')` is called in order for the `render` event to fire, though you can manually do a `this.trigger('render')` instead, if you want.\n\n### setElement\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object|String} element`, optional `{Object} events`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nA public method that allows you to change or set an element that powers a view. If called the first time, it will get the Element (through Sizzle / `jQuery()`) and save a reference in `this.element` to the raw object, as well as `this.$element` to the wrapped jQuery object. If an events object is passed, it will bind the events. If called a second time, it will unbind all events on the old element, change the element reference and rebind any new events.\n\n### template\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} data`, optional `{String} template`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: compiled template or function._\n\u003c/p\u003e\n\u003c/div\u003e\n\nA simple sandbox function where you can either use the lodash templating engine or call an external engine like Mustache, Handlebars, Hogan etc. The second argument is optional and if not supplied, it will revert to `this.options.template` instead.\n\nAn example override to make it work with Mustache would be:\n```javascript\nvar myView = epik.primish({\n\textends: epik.view,\n\ttemplate: function(data, template) {\n\t\ttemplate = template || this.options.template;\n\t\treturn Mustache.render(template, data);\n\t},\n\trender: function() {\n\t\tthis.$element.html(this.template(this.model.toJSON(), 'Hello {{name}}'));\n\t}\n});\n```\n\nYou can change the View prototype to always have Mustache in your views. For example, via AMD/RequireJS, you could do a\nsmall module that deals with the prototyping of the default View constructor. Say, `epitome-view-mustache.js`\n```javascript\n\ndefine(['epik/view'], function(View){\n\t// for everyone to use mustache in every view instance when .template()\n\n\tView.prototype.template = function(data, template) {\n\t\t// refactor this to work with any other template engine in your constructor\n\t\ttemplate = template || this.options.template;\n\n\t\treturn Mustache.render(template, data);\n\t}\n\n\treturn View;\n});\n```\n\n### empty\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Boolean} soft`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `empty`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nBy default, it will empty the element through making `innerHTML` an empty string, calling GC on all child nodes. If the `soft` argument is true, will apply `this.$element.empty()`, which is a jQuery method that removes all child nodes without destroying them.\n\n### dispose\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`._\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `dispose`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nWill detach `this.$element` from the DOM. It can be injected again later on.\n\n### destroy\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: none_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `viewInstance`._\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `dispose`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves and destroys `this.$element` from the DOM and from memory. You need to use [setElement](#view/setelement) to add a new one if you want to re-render.\n\n\n## View rivets-adapter\n\nThere is an adapter for rivets.js provided, which does the following customisations:\n\n - prefix is `ep-` for your data bindings\n - the adapter suffix is `#`\n\nExample view implementation:\n```ace\nrequire([\n\t'epik/index',\n\t'epik/view',\n\t'epik/model',\n\t'epik/plugins/rivets-adapter'\n], function(epik, View, Model, rivets) {\n\n\tvar primish = epik.primish;\n\n\tvar MyView = primish({\n\t\t// mixin the rivets class\n\t\timplement: [rivets],\n\t\textend: View,\n\t\toptions: {\n\t\t\ttemplate: ''\n\t\t},\n\t\tconstructor: function(options){\n\t\t\tthis.parent('constructor', options);\n\t\t\tthis.element.innerHTML = this.options.template;\n\t\t\tthis.bindRivets(this.element, {\n\t\t\t\tperson: this.model\n\t\t\t});\n\t\t},\n\t\tdestroy: function(){\n\t\t\tthis.unbindRivets();\n\t\t\tthis.parent('destroy');\n\t\t}\n\t});\n\n\tvar person = new Model({\n\t\tname: 'Bob'\n\t});\n\n\t// new view with bi-directional binding between model and dom.\n\tvar myView = new MyView({\n\t\telement: document.getElementById('main'),\n\t\tmodel: person,\n\t\ttemplate: 'Name: \u003cspan ep-text=\"person#name\"\u003e\u003c/span\u003e\u003cbr/\u003e\u003cinput ep-value=\"person#name\"/\u003e'\n\t});\n\n\tsetTimeout(function(){\n\t\tperson.set('name', 'Robert');\n\t}, 1500);\n});\n```\n\nAny change of the model will fire events which the adapter is listening for and will automatically update the view\nfor the relevant bound nodes. Conversely, changes from the DOM via conventional `onChange` events will be exported\nto the model's `.set()` method (subject to validation rules).\n\nCollections are similarly implemented. Notice the use of `ep-` as opposed to `rv-` and the `#` call to pass through\nthe epik adapter (the rivets default PJSO one is `.` and it can still be used)\n\nThe full spectrum of Rivets.js API will work as expected.\n\n### bindRivets\n\nSugar that passes an object to be bound to `this.element`. Optionally, you can pass a different element as the first\nargument. Creates a `this.boundRivets` property on the object, containing reference to the current rivet view context instance\n\n### unbindRivets\n\nUsed as a destructor to unbind existing events from `this.boundRivets`\n\n### syncRivets\n\nA method that calls `rivets.sync()` on the bound view to force manual processing, like `$digest`\n\n\n## router\n\nThe Router prime is a hashbang controller, useful for single page applications. Currently, it works with `window.onhashchange` and a `setInterval` polyfill for older browsers. It may change to push/pop state soon.\n\n### constructor\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} options`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `routerInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `ready`, `before`, `after`, mixed, `undefined`, `error`, `route:add`, `route:remove`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nAs this is quite involved and can act as a Controller for your app, here's a practical example that defines a few routes and event handlers within the epik.router prime instantiation:\n\n```javascript\nApp.router = new epik.router({\n\t// routes definition will proxy the events\n\troutes: {\n\t\t''\t\t\t\t\t\t: 'index',\n\t\t'#!help'\t\t\t\t: 'help',\n\t\t'#!test1/:query/:id?'\t: 'test1',\n\t\t'#!test2/:query/*'\t\t: 'test2',\n\t\t'#!error'\t\t\t\t: 'dummyerror'\n\t},\n\n\t// router init\n\tonReady: function(){\n\t\tconsole.log('init');\n\t},\n\n\t// before route method, fires before the event handler once a match has been found\n\tonBefore: function(routeId){\n\t\tconsole.log('before', routeId)\n\t},\n\n\t// specific pseudos for :before\n\t'onIndex:before': function() {\n\t\tconsole.log('we are about to go to the index route');\n\t},\n\n\t// specific pseudos for after\n\t'onIndex:after': function() {\n\t\tconsole.log('navigated already to index route, update breadcrumb?');\n\t},\n\n\t// after route method has fired, post-route event.\n\tonAfter: function(route){\n\t\tconsole.info('after', route)\n\t},\n\n\t// routes events callbacks are functions that call parts of your app\n\n\t// index\n\tonIndex: function() {\n\t\tconsole.log('index')\n\t},\n\n\tonHelp: function() {\n\t\tconsole.log('help');\n\t\tconsole.log(this.route, this.req, this.param, this.query)\n\t},\n\n\tonTest1: function(query, id) {\n\t\tconsole.info('test1', query, id);\n\t\tconsole.log(this.route, this.req, this.param, this.query)\n\t},\n\n\tonTest2: function(query) {\n\t\tconsole.info('test2', query);\n\t\tconsole.log(this.route, this.req, this.param, this.query)\n\t},\n\n\t// no route event was found, though route was defined\n\tonError: function(error){\n\t\tconsole.error(error);\n\t\t// recover by going default route\n\t\tthis.navigate('');\n\t},\n\n\tonUndefined: function() {\n\t\tconsole.log('this is an undefined route');\n\t},\n\n\t'onRoute:remove': function(route) {\n\t\talert(route + ' was removed by popular demand');\n\t},\n\n\t'onRoute:add': function(constructorObject) {\n\t\tconsole.log(constructorObject.id + ' was added as a new route');\n\t}\n});\n```\n### addRoute\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{Object} route`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `routerInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `route:add`_\n\u003cp\u003e\n\u003c/div\u003e\n\nExample late adding of route to your instance (after instantiation):\n\n```javascript\nApp.router.addRoute({\n\troute: '#!dynamicRoute',\n\tid: 'dynamic',\n\tevents: {\n\t\tonDynamic: function() {\n\t\t\talert('you found the blowfish');\n\t\t\tif (confirm('remove this route?'))\n\t\t\t\tthis.removeRoute('#!dynamicRoute');\n\t\t}\n\t}\n});\n```\n\n### removeRoute\n---\n\u003cdiv class=\"alert\"\u003e\n\u003cp\u003e\n_Expects arguments: `{String} route`_\n\u003c/p\u003e\n\u003cp\u003e\n_Returns: `routerInstance`_\n\u003c/p\u003e\n\u003cp\u003e\n_Events: `route:remove`_\n\u003c/p\u003e\n\u003c/div\u003e\n\nRemoves a route by the route identifier string.\n\nFor more examples of Router, have a look inside the `dist/example` folder, it's powered by a router instance.\n\n## Contributing\n\nWhilst this is being ported, you can help. Fork the repo or ask for commit access.\n\n```sh\n$ git clone git@github.com:DimitarChristoff/epik.git\n...\n$ cd epik/\n$ npm i\n...\n$ bower install\n...\n$ cd test/\n$ buster-static\n...\n```\n\nExamples - run a grunt express server with socket.io etc. Install grunt if you don't have it, then run from root of the repo.\n\n```sh\n$ npm install -g grunt-cli\n$ grunt\n$ grunt build\n$ grunt requirejs\n```\n\nThe web server is on port 8000 - visit [http://locahost:8000/example/](http://locahost:8000/example/) to view live examples\n\nA nice example of a practical web app running mocked FX currency pairs is here: [https://github.com/DimitarChristoff/cp](https://github.com/DimitarChristoff/cp). It has been written to test the speed of bindings via the rivets adapter and should work fine\nwith as many as 200+ currency pairs running and streaming via socket.io under chrome, all at no more than 20-30% CPU use.\n\nYou can view it in action [http://fragged.org:8000/](here) - if the grunt server is up.\n\nA TodoMVC implementation can be seen [here](https://github.com/epitome-mvc/todomvc/tree/epik/labs/dependency-examples/epik)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimitarchristoff%2Fepik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdimitarchristoff%2Fepik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimitarchristoff%2Fepik/lists"}