{"id":20461034,"url":"https://github.com/ericgj/model","last_synced_at":"2025-06-30T16:39:06.251Z","repository":{"id":18346092,"uuid":"21525883","full_name":"ericgj/model","owner":"ericgj","description":"Simple, framework-agnostic, persistent models for the browser","archived":false,"fork":false,"pushed_at":"2015-07-07T19:42:41.000Z","size":224,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-05T11:34:19.755Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"shengxinjing/programmer-job-blacklist","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericgj.png","metadata":{"files":{"readme":"Readme.md","changelog":"History.md","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":"2014-07-05T18:40:16.000Z","updated_at":"2015-07-07T19:42:02.000Z","dependencies_parsed_at":"2022-08-25T12:11:17.200Z","dependency_job_id":null,"html_url":"https://github.com/ericgj/model","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ericgj/model","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fmodel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fmodel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fmodel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fmodel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericgj","download_url":"https://codeload.github.com/ericgj/model/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericgj%2Fmodel/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262811453,"owners_count":23368112,"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-11-15T12:22:56.205Z","updated_at":"2025-06-30T16:39:06.231Z","avatar_url":"https://github.com/ericgj.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# model\n\n  Simple, framework-agnostic, persistent models for the browser.\n\n  * Declarative attributes based on [JSON Schema][jsonschema]\n  * Defaults\n  * Customizable type casting\n  * Observable `set` and `reset`\n  * No sync layer\n\n## Installation\n\n  Install with [component(1)](http://component.io):\n\n    $ component install ericgj/model\n\n\u003ca name=\"api\"\u003e\u003c/a\u003e\n## API\n\n\u003ca name=\"api_model\"\u003e#\u003c/a\u003e var model = \u003cb\u003erequire('model')\u003c/b\u003e()\n\nModel constructor.\n\n\u003ca name=\"api_model_attr\"\u003e#\u003c/a\u003e\u003cbr/\u003e \nmodel.\u003cb\u003eattr\u003c/b\u003e(\u003ci\u003ename\u003c/i\u003e [, \u003ci\u003eschema\u003c/i\u003e])\u003cbr/\u003e\nmodel.\u003cb\u003eattr\u003c/b\u003e(\u003ci\u003eobject\u003c/i\u003e)\n\nDefine attribute `name` with given `schema` object. The schema can specify \na default value (`default`), a data type (`type`), and whether or not the\nattribute is read-only (`readOnly`).\n\nThe single-argument form allows you to specify multiple attributes by passing\nan object whose keys are attribute names and whose values are schemas.\n\n\u003ca name=\"api_model_cast\"\u003e#\u003c/a\u003e\u003cbr/\u003e\nmodel.\u003cb\u003ecast\u003c/b\u003e(\u003ci\u003ename\u003c/i\u003e, \u003ci\u003efunction\u003c/i\u003e)\u003cbr/\u003e\nmodel.\u003cb\u003ecast\u003c/b\u003e(\u003ci\u003eobject\u003c/i\u003e)\n\nDefine a custom conversion function for the specified attribute `name`. When\n`type` is specified for an attribute, the attribute is cast using build-in cast\nfunctions. Specifying `cast` overrides this default casting.  \n\nTypically, `cast` is used in converting string values (from CSV data or view\ninput elements, for instance), into a useful representation.\n\nFor instance:\n\n```js\n  model.attr('tags',  { type: 'string' })\n       .attr('count', { type: 'number' })\n       .cast('tags',  function(s){ return String(s).split(','); }) \n       .cast('count', function(s){ return +s; }) \n```\n\nThe single-argument form allows you to specify multiple casts by passing\nan object whose keys are attribute names and whose values are cast functions.\n\n\u003ca name=\"api_model_calc\"\u003e#\u003c/a\u003e\u003cbr/\u003e \nmodel.\u003cb\u003ecalc\u003c/b\u003e(\u003ci\u003ename\u003c/i\u003e, \u003ci\u003efunction\u003c/i\u003e)\u003cbr/\u003e\nmodel.\u003cb\u003ecalc\u003c/b\u003e(\u003ci\u003eobject\u003c/i\u003e)\n\nDefine a calculated attribute `name` using the specified `function`. Note the\nfunction is called on the _casted_ current value, not the raw value.\n\nThe single-argument form allows you to specify multiple calculations by passing\nan object whose keys are attribute names and whose values are calc functions.\n\n\n\u003ca name=\"api_instance\"\u003e#\u003c/a\u003e var instance = \u003cb\u003emodel\u003c/b\u003e([\u003ci\u003eobject\u003c/i\u003e])\n\nConstruct an instance of the model by calling the model as a function. If \n`object` is passed, it extends the default.\n\n\u003ca name=\"api_instance_value\"\u003e#\u003c/a\u003e instance.\u003cb\u003evalue\u003c/b\u003e()\n\nGet the current value (plain object) of the instance. Attributes are casted\nif their type or an explicit cast has been specified. Attributes on the\noriginal object that are not specified in the model are passed through\nunchanged. Calculated attributes are also included.\n\n\u003ca name=\"api_instance_changedValue\"\u003e#\u003c/a\u003e instance.\u003cb\u003echangedValue\u003c/b\u003e()\n\nGet the _changed_ value (plain object) of the instance. All specified,\nnon-read-only attributes with a current value are included. Read-only and\nunspecified attributes are _not_ included, nor are calculated attributes.\n\n\u003ca name=\"api_instance_change\"\u003e#\u003c/a\u003e instance.\u003cb\u003echange\u003c/b\u003e()\n\nGet an object representing the applied changes made to attributes. Useful for\n`PATCH`-style updates.\n\n\u003ca name=\"api_instance_changes\"\u003e#\u003c/a\u003e instance.\u003cb\u003echanges\u003c/b\u003e()\n\nGet an array of all changes as `[attribute, value]` pairs.\n\n\u003ca name=\"api_instance_dirty\"\u003e#\u003c/a\u003e instance.\u003cb\u003edirty\u003c/b\u003e()\n\nSugar for `instance.changes().length \u003e 0` .\n\n\u003ca name=\"api_instance_get\"\u003e#\u003c/a\u003e instance.\u003cb\u003eget\u003c/b\u003e(\u003ci\u003eattribute\u003c/i\u003e)\n\nGet the current (casted) value of the attribute.\n\n\u003ca name=\"api_instance_set\"\u003e#\u003c/a\u003e\u003cbr/\u003e\ninstance.\u003cb\u003eset\u003c/b\u003e(\u003ci\u003eattribute\u003c/i\u003e, \u003ci\u003evalue\u003c/i\u003e) \u003cbr/\u003e\ninstance.\u003cb\u003eset\u003c/b\u003e(\u003ci\u003eobject\u003c/i\u003e)\n\nSet an attribute (or attributes if an object is passed). If the attribute is \n`readOnly`, or attribute is not specified in the model, `set` has no effect.\n\nDispatches a 'set' event with the attribute and value as parameters. See\nbelow, [Events](#events).\n\n\u003ca name=\"api_instance_reset\"\u003e#\u003c/a\u003e instance.\u003cb\u003ereset\u003c/b\u003e([\u003ci\u003eobject\u003c/i\u003e])\n\nResets internal state of the instance without losing event observers. In\nother words, it's equivalent to creating a new model instance, except that \nany event observers on the instance are maintained. If no \u003ci\u003eobject\u003c/i\u003e is \npassed, then it simply clears the changes but does not change the underlying\nbase object passed in the constructor. Dispatches a 'reset' event. \n\n\n\u003ca name=\"events\"\u003e\u003c/a\u003e\n## Events\n\nEvents can be observed either at the _model_ or _instance_ level. The callback\nsignature is the same, except the model events have the instance as the first\nparameter. If you have used [component/model][compmodel] or [modella][modella], \nthis should seem familiar. \n\n\u003ca name=\"api_events_set\"\u003e#\u003c/a\u003e\u003cbr/\u003e\nmodel.on(\u003cb\u003e'set'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e) \u003cbr/\u003e\ninstance.on(\u003cb\u003e'set'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e)\n\nFired on `instance.set`, calling the handler with the passed attribute and\nvalue. Note `set(object)` calls result in multiple `set` events, one per\nattribute-value pair.\n\n\u003ca name=\"api_events_reset\"\u003e#\u003c/a\u003e\u003cbr/\u003e\nmodel.on(\u003cb\u003e'reset'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e) \u003cbr/\u003e\ninstance.on(\u003cb\u003e'reset'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e)\n\nFired on `instance.reset`, calling the handler with the passed object.\nNote this is the \"raw\" passed object, not the `model.value()`.\n\n\u003ca name=\"api_events_setting\"\u003e#\u003c/a\u003e\u003cbr/\u003e\nmodel.on(\u003cb\u003e'setting'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e) \u003cbr/\u003e\ninstance.on(\u003cb\u003e'setting'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e)\n\nSame as `set`, but fired _before_ state changes.\n\n\u003ca name=\"api_events_resetting\"\u003e#\u003c/a\u003e\u003cbr/\u003e\nmodel.on(\u003cb\u003e'resetting'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e) \u003cbr/\u003e\ninstance.on(\u003cb\u003e'resetting'\u003c/b\u003e, \u003ci\u003ehandler\u003c/i\u003e)\n\nSame as `reset`, but fired _before_ state changes.\n\nNote that `setting` and `resetting` events can be used to check existing\nstate in an event handler:\n\n```js\n  model.on('setting', function(instance,attr,val){\n    var oldval = instance.get(attr);\n    // do something comparing oldval with val \n  })\n\n  instance.on('resetting', function(obj){\n    var oldobj = instance.value()\n    // do something comparing oldobj with obj\n  })\n\n```\n\n## TODO\n\n  * metadata\n  * validation\n  * model construction directly via JSON Schema\n\n\n## License\n\n  The MIT License (MIT)\n\n  Copyright (c) 2014 Eric Gjertsen `\u003cericgj72@gmail.com\u003e`\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n\n\n[jsonschema]: http://json-schema.org\n[compmodel]:  https://github.com/component/model\n[modella]:    https://github.com/modella/modella\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgj%2Fmodel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericgj%2Fmodel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericgj%2Fmodel/lists"}