mirror of
https://github.com/frappe/books.git
synced 2024-11-08 23:00:56 +00:00
docs
This commit is contained in:
parent
234eb9dea1
commit
0fa2c70133
318
README.md
318
README.md
@ -1,313 +1,19 @@
|
||||
# Frappe Core
|
||||
# Frappe.JS
|
||||
|
||||
Core libs for Frappe Framework JS
|
||||
Frappe.js is a meta-data driven framework that enables rapid application development of Node.js and Electron based applications.
|
||||
|
||||
## Declaring Models
|
||||
## Features
|
||||
|
||||
Models are declared by adding a `.json` model file in the `models/doctype` folder of the module/app.
|
||||
- Rapid Application Development
|
||||
- Single Page App
|
||||
- Forms and Controls
|
||||
- REST-API
|
||||
- Database backends
|
||||
|
||||
```json
|
||||
{
|
||||
"autoname": "hash",
|
||||
"name": "ToDo",
|
||||
"doctype": "DocType",
|
||||
"issingle": 0,
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "subject",
|
||||
"label": "Subject",
|
||||
"fieldtype": "Data",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"label": "Description",
|
||||
"fieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"label": "Status",
|
||||
"fieldtype": "Select",
|
||||
"options": [
|
||||
"Open",
|
||||
"Closed"
|
||||
],
|
||||
"default": "Open",
|
||||
"reqd": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
## Documentation
|
||||
|
||||
## Setup / Migrate
|
||||
[Read the full docs](docs/README.md)
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// sync all schema from `models` folders in all apps
|
||||
await frappe.migrate();
|
||||
```
|
||||
|
||||
## Managing Documents
|
||||
|
||||
Frappe Object-Relational-Mapper (ORM) helps you manage (create, read, update, delete) documents based on the DocTypes declared.
|
||||
|
||||
Documents are sub-classed from the `frappe.document.Document` class.
|
||||
|
||||
All document write methods are asynchronous and return javascript Promise objects.
|
||||
|
||||
### Initialize
|
||||
|
||||
Documents are initialized with the `frappe.get_doc` method. If `doctype` and `name` are passed as parameters, then the document is fetched from the backend. If a simple object is passed, then object properties are set in the document.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// make a new todo
|
||||
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
|
||||
```
|
||||
|
||||
### Create
|
||||
|
||||
You can insert a document in the backend with the `insert` method.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// make a new todo
|
||||
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
|
||||
await todo.insert();
|
||||
```
|
||||
|
||||
### Read
|
||||
|
||||
You can read a document from the backend with the `frappe.get_doc` method
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
The `update` method updates a document.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
|
||||
first_todo.status = 'Closed';
|
||||
await first_todo.update();
|
||||
```
|
||||
|
||||
### Delete
|
||||
|
||||
The `delete` method deletes a document.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
|
||||
await first_todo.delete();
|
||||
```
|
||||
|
||||
## Metadata
|
||||
|
||||
Metadata are first class objects in Frappe. You can get a metadata object by `frappe.get_meta`. All objects from the `models` folders of all modules are loaded.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
let todo_meta = frappe.get_meta('ToDo');
|
||||
|
||||
// get all fields of type "Data"
|
||||
let data_fields = todo_meta.fields.map(d => d.fieldtype=='Data' ? d : null);
|
||||
```
|
||||
|
||||
## Controllers
|
||||
|
||||
You can write event handlers in controllers, by declaring a `.js` file in the `models/doctype/` folder along with the model file.
|
||||
|
||||
The name of the class must be the slugged name of the DocType
|
||||
|
||||
To add a standard handler, you must bind all handlers in `setup` method.
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
class todo extends frappe.document.Document {
|
||||
setup() {
|
||||
this.add_handler('validate');
|
||||
}
|
||||
|
||||
validate() {
|
||||
// set default status as "Open" if not set
|
||||
if (!this.status) {
|
||||
this.status = 'Open';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { todo: todo };
|
||||
```
|
||||
|
||||
### Controller Events
|
||||
|
||||
Standard events on which you can bind handlers are
|
||||
|
||||
- `before_insert`
|
||||
- `before_update`
|
||||
- `validate` (called before any write)
|
||||
- `after_insert`,
|
||||
- `after_update` (called after any write)
|
||||
- `before_submit`
|
||||
- `after_submit`
|
||||
- `before_cancel`
|
||||
- `after_cancel`
|
||||
- `before_delete`
|
||||
- `after_delete`
|
||||
|
||||
## Database
|
||||
|
||||
You can also directly write SQL with `frappe.db.sql`
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
await frappe.init();
|
||||
await frappe.init_db('sqlite', {db_path: 'test.db'});
|
||||
|
||||
all_todos = frappe.db.sql('select name from todo');
|
||||
```
|
||||
|
||||
## REST API
|
||||
|
||||
You can directly access documents at `/api/resource/:doctype`
|
||||
|
||||
### Create
|
||||
|
||||
- URL: `/api/resource/:doctype`
|
||||
- Method: `POST`
|
||||
- Data: document properties
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo`
|
||||
- Method: `POST`
|
||||
|
||||
Data:
|
||||
|
||||
```json
|
||||
{
|
||||
"subject": "test",
|
||||
"description": "test description"
|
||||
}
|
||||
```
|
||||
|
||||
### Read
|
||||
|
||||
- URL: `/api/resource/:doctype/:name`
|
||||
- Method: `GET`
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo/uig7d1v12`
|
||||
|
||||
Reponse:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "uig7d1v12",
|
||||
"owner": "guest",
|
||||
"modified_by": "guest",
|
||||
"creation": "2018-01-01T12:08:19.482Z",
|
||||
"modified": "2018-01-01T12:08:19.482Z",
|
||||
"docstatus": 0,
|
||||
"subject": "test 1",
|
||||
"description": "description 1",
|
||||
"status": "Open"
|
||||
}
|
||||
```
|
||||
|
||||
### List
|
||||
|
||||
- URL: `/api/resource/:doctype/`
|
||||
- Method: `GET`
|
||||
- Params (optional)
|
||||
- `start`: Page start
|
||||
- `limit`: Page limit
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "r4qxyki0i6",
|
||||
"subject": "test 1"
|
||||
},
|
||||
{
|
||||
"name": "efywwvtwcp",
|
||||
"subject": "test 1"
|
||||
},
|
||||
{
|
||||
"name": "9ioz05urgp",
|
||||
"subject": "test 1"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## REST Client
|
||||
|
||||
Frappe comes with a built in REST client so you can also use REST as a database backend with the frappe API
|
||||
|
||||
### Create, Read, Update, Delete
|
||||
|
||||
You can manage documents, using the same Document API as if it were a local database
|
||||
|
||||
```js
|
||||
await frappe.init();
|
||||
await frappe.init_db('rest', {server: 'localhost:8000'});
|
||||
|
||||
let doc = await frappe.get_doc({doctype:'ToDo', subject:'test rest insert 1'});
|
||||
await doc.insert();
|
||||
|
||||
doc.subject = 'subject changed';
|
||||
await doc.update();
|
||||
|
||||
let data = await frappe.db.get_all({doctype:'ToDo'});
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
All tests are in the `tests` folder and are run using `mocha`. To run tests
|
||||
|
||||
```sh
|
||||
npm run test
|
||||
```
|
||||
## License
|
||||
|
||||
MIT
|
@ -2,13 +2,12 @@ const frappe = require('frappe-core');
|
||||
const path = require('path');
|
||||
|
||||
class RESTClient {
|
||||
constructor({server, protocol='http', fetch}) {
|
||||
constructor({server, protocol='http'}) {
|
||||
this.server = server;
|
||||
this.protocol = protocol;
|
||||
|
||||
this.init_type_map();
|
||||
|
||||
frappe.fetch = fetch;
|
||||
this.json_headers = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -11,9 +11,13 @@ class Form {
|
||||
this.controls_list = [];
|
||||
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
this.make();
|
||||
}
|
||||
|
||||
make() {
|
||||
if (this.body || !this.parent) {
|
||||
return;
|
||||
}
|
||||
this.body = frappe.ui.add('form', null, this.parent);
|
||||
for(let df of this.meta.fields) {
|
||||
if (controls.get_control_class(df.fieldtype)) {
|
||||
|
@ -2,22 +2,43 @@ const frappe = require('frappe-core');
|
||||
|
||||
class Page {
|
||||
constructor(title) {
|
||||
this.handlers = {};
|
||||
this.title = title;
|
||||
this.make();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.body = frappe.ui.add('div', 'page hide', frappe.main);
|
||||
}
|
||||
|
||||
hide() {
|
||||
frappe.ui.add_class(this.body, 'hide');
|
||||
|
||||
this.trigger('hide');
|
||||
}
|
||||
show() {
|
||||
|
||||
show(params) {
|
||||
if (frappe.router.current_page) {
|
||||
frappe.router.current_page.hide();
|
||||
}
|
||||
frappe.ui.remove_class(this.body, 'hide');
|
||||
frappe.router.current_page = this;
|
||||
document.title = this.title;
|
||||
|
||||
this.trigger('show', params);
|
||||
}
|
||||
|
||||
on(event, fn) {
|
||||
if (!this.handlers[event]) this.handlers.event = [];
|
||||
this.handlers[event].push(fn);
|
||||
}
|
||||
|
||||
trigger(event, params) {
|
||||
if (this.handlers[event]) {
|
||||
for (let handler of this.handlers[event]) {
|
||||
handler(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
21
frappe/docs/README.md
Normal file
21
frappe/docs/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Frappe.js
|
||||
|
||||
Frappe.js is a meta-data driven framework that enables rapid application development of Node.js and Electron based applications.
|
||||
|
||||
## Contents
|
||||
|
||||
- Models and Documents
|
||||
- [Declaring Models](models.md)
|
||||
- [Controllers](controllers.md)
|
||||
- [Metadata](metadata.md)
|
||||
- [Managing Documents](documents.md)
|
||||
- [Server](server.md)
|
||||
- [REST API](rest.md)
|
||||
- [Client](client.md)
|
||||
- [Routing](routing.md)
|
||||
- [Page](page.md)
|
||||
- [Lists](lists.md)
|
||||
- [Forms](forms.md)
|
||||
- [Controls](controls.md)
|
||||
- [Backends](backends.md)
|
||||
- [Testing](testing.md)
|
49
frappe/docs/backends.md
Normal file
49
frappe/docs/backends.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Backends
|
||||
|
||||
Frappe.js comes with built-in backends for data storage. These can be client-side or server-side
|
||||
|
||||
- SQLite
|
||||
- REST
|
||||
|
||||
There can be only one backend at a time that can be accessed by the `frappe.db` property.
|
||||
|
||||
## API
|
||||
|
||||
The backend will implement the following `async` methods
|
||||
|
||||
- `get_doc`
|
||||
- `get_all`
|
||||
- `get_value`
|
||||
- `insert`
|
||||
- `update`
|
||||
|
||||
## sqlite Backend
|
||||
|
||||
Connection paramter required for the sqlite backend is the path of the file
|
||||
|
||||
```js
|
||||
sqllite = require('frappe-core/frappe/backends/sqlite');
|
||||
|
||||
frappe.db = await new sqlite.Database({db_path: db_path})
|
||||
```
|
||||
|
||||
### SQL Queries
|
||||
|
||||
You can also directly write SQL with `frappe.db.sql`
|
||||
|
||||
```js
|
||||
all_todos = frappe.db.sql('select name from todo');
|
||||
```
|
||||
|
||||
## REST Backend
|
||||
|
||||
For the client, the backend is the REST API that executes calls with web-requests.
|
||||
|
||||
Before using, you must initialize the `frappe.fetch` property with `window.fetch` or `node-fetch`
|
||||
|
||||
```js
|
||||
const Database = require('frappe-core/frappe/backends/rest_client').Database;
|
||||
|
||||
frappe.fetch = window.fetch.bind();
|
||||
frappe.db = await new Database({server: server});
|
||||
```
|
60
frappe/docs/client.md
Normal file
60
frappe/docs/client.md
Normal file
@ -0,0 +1,60 @@
|
||||
# Client
|
||||
|
||||
Frappe.js comes with built in single-page-application (SPA) with routing, views, list and form objects.
|
||||
|
||||
In building the client, you can use the REST API to query data, and use the models and controllers declared in your module.
|
||||
|
||||
You can use the same document API in the client as in the server, the only difference being that the data will be fetched via REST API in the background.
|
||||
|
||||
## Routing
|
||||
|
||||
- [Router](router.md)
|
||||
|
||||
## Views
|
||||
|
||||
- [Page](page.md)
|
||||
- [List](list.md)
|
||||
- [Form](form.md)
|
||||
|
||||
## Starting
|
||||
|
||||
You can setup your client by setting up the server and then importing your controllers with `require`
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const client = require('frappe-core/frappe/client');
|
||||
|
||||
client.start({
|
||||
server: 'localhost:8000',
|
||||
container: document.querySelector('.container'),
|
||||
}).then(() => {
|
||||
const todo = require('frappe-core/frappe/models/doctype/todo/todo.js');
|
||||
frappe.init_controller('todo', todo);
|
||||
|
||||
// ....
|
||||
});
|
||||
```
|
||||
|
||||
## REST Client
|
||||
|
||||
Frappe.js comes with a built in REST client so you can also use REST as a database backend with the Frappe.js API
|
||||
|
||||
### Create, Read, Update, Delete
|
||||
|
||||
You can manage documents, using the same Document API as if it were a local database
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
await frappe.init();
|
||||
await frappe.init_db('rest', {server: 'localhost:8000'});
|
||||
|
||||
let doc = await frappe.get_doc({doctype:'ToDo', subject:'test rest insert 1'});
|
||||
await doc.insert();
|
||||
|
||||
doc.subject = 'subject changed';
|
||||
await doc.update();
|
||||
|
||||
let data = await frappe.db.get_all({doctype:'ToDo'});
|
||||
```
|
65
frappe/docs/controllers.md
Normal file
65
frappe/docs/controllers.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Controllers
|
||||
|
||||
In Frappe.js you can extend the metadata class as well as the document class for a particular DocType. The `meta` class contains actions that are done on a group of objects and a document represents a single object. So properties and actions related to the group will be part of the `meta` class
|
||||
|
||||
You can write event handlers in controllers, by declaring a `.js` file in the `models/doctype/` folder along with the model file.
|
||||
|
||||
### Naming
|
||||
|
||||
1. The name of the controller class must be the slugged name of the DocType (example `todo`)
|
||||
2. The name of the `meta` class must be the name of the controller class prefixed by `meta_` (example `meta_todo`)
|
||||
|
||||
To add a standard handler, you must bind all handlers in `setup` method.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const frappe = require('frappe-core');
|
||||
|
||||
// extend the meta class
|
||||
class todo_meta extends frappe.meta.Meta {
|
||||
setup_meta() {
|
||||
Object.assign(this, require('./todo.json'));
|
||||
this.name = 'ToDo';
|
||||
this.list_options.fields = ['name', 'subject', 'status', 'description'];
|
||||
}
|
||||
|
||||
get_row_html(data) {
|
||||
return `<a href="#edit/todo/${data.name}">${data.subject}</a>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// extend the document and add event handlers
|
||||
class todo extends frappe.document.Document {
|
||||
setup() {
|
||||
this.add_handler('validate');
|
||||
}
|
||||
validate() {
|
||||
if (!this.status) {
|
||||
this.status = 'Open';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
todo: todo,
|
||||
todo_meta: todo_meta
|
||||
};
|
||||
```
|
||||
|
||||
### Controller Events
|
||||
|
||||
Standard events on which you can bind handlers are
|
||||
|
||||
- `before_insert`
|
||||
- `before_update`
|
||||
- `validate` (called before any write)
|
||||
- `after_insert`,
|
||||
- `after_update` (called after any write)
|
||||
- `before_submit`
|
||||
- `after_submit`
|
||||
- `before_cancel`
|
||||
- `after_cancel`
|
||||
- `before_delete`
|
||||
- `after_delete`
|
42
frappe/docs/controls.md
Normal file
42
frappe/docs/controls.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Controls
|
||||
|
||||
Frappe.js comes in with built-in controls for various types of inputs
|
||||
|
||||
## Creating
|
||||
|
||||
A new control can be created with `control.make_control` method.
|
||||
|
||||
```js
|
||||
const controls = require('./controls');
|
||||
|
||||
let control = controls.make_control({
|
||||
fieldname: 'test',
|
||||
fieldtype: 'Data',
|
||||
label: 'Test Control'
|
||||
}, body);
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
The control has the following structure of HTML Elements
|
||||
|
||||
- `form_group`
|
||||
- `label`
|
||||
- `input`
|
||||
- `description`
|
||||
|
||||
## Types
|
||||
|
||||
Type of control is defined by the `fieldtype` property.
|
||||
|
||||
### Data
|
||||
|
||||
Short text input (`<input>`)
|
||||
|
||||
## Text
|
||||
|
||||
Long text input (`<textarea>`)
|
||||
|
||||
## Select
|
||||
|
||||
Select a single value from a list of options (`<select>`)
|
65
frappe/docs/document.md
Normal file
65
frappe/docs/document.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Managing Documents
|
||||
|
||||
Frappe.js Object-Relational-Mapper (ORM) helps you manage (create, read, update, delete) documents based on the DocTypes declared.
|
||||
|
||||
Documents are sub-classed from the `frappe.document.Document` class.
|
||||
|
||||
All document write methods are asynchronous and return javascript Promise objects.
|
||||
|
||||
### Initialize
|
||||
|
||||
Documents are initialized with the `frappe.get_doc` method. If `doctype` and `name` are passed as parameters, then the document is fetched from the backend. If a simple object is passed, then object properties are set in the document.
|
||||
|
||||
```js
|
||||
// make a new todo
|
||||
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
|
||||
```
|
||||
|
||||
### Create
|
||||
|
||||
You can insert a document in the backend with the `insert` method.
|
||||
|
||||
```js
|
||||
// make a new todo
|
||||
let todo = await frappe.get_doc({doctype: 'ToDo', subject: 'something'});
|
||||
await todo.insert();
|
||||
```
|
||||
|
||||
### Read
|
||||
|
||||
You can read a document from the backend with the `frappe.get_doc` method
|
||||
|
||||
```js
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
The `update` method updates a document.
|
||||
|
||||
```js
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
|
||||
first_todo.status = 'Closed';
|
||||
await first_todo.update();
|
||||
```
|
||||
|
||||
### Delete
|
||||
|
||||
The `delete` method deletes a document.
|
||||
|
||||
```js
|
||||
// get all open todos
|
||||
let todos = await frappe.db.get_all({doctype:'ToDo', fields:['name'], filters: {status: "Open"});
|
||||
let first_todo = await frappe.get_doc('ToDo', toods[0].name);
|
||||
|
||||
await first_todo.delete();
|
||||
```
|
||||
|
||||
### Extending Documents
|
||||
|
||||
Each model can be extended by adding events in the [controller](controllers.md) class.
|
63
frappe/docs/forms.md
Normal file
63
frappe/docs/forms.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Forms
|
||||
|
||||
Forms are automatically created from the model (DocType)
|
||||
|
||||
Form objects create the controls and also handler insert and update.
|
||||
|
||||
Note: A single Form object can handle multiple documents.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const Page = require('frappe-core/frappe/client/view/page').Page;
|
||||
const Form = require('frappe-core/frappe/client/view/form').Form;
|
||||
|
||||
edit_page = new Page('Edit To Do');
|
||||
|
||||
router.add('/edit/todo/:name', edit_page);
|
||||
|
||||
edit_page.form = new Form({
|
||||
doctype: 'ToDo',
|
||||
parent: edit_page.body
|
||||
});
|
||||
```
|
||||
|
||||
## Creating
|
||||
|
||||
To create a new Form, you need to pass the model (DocType) and `parent` element.
|
||||
|
||||
Controls will be created for all the `fields` of the model that is passed along with a `Submit` button
|
||||
|
||||
## Editing
|
||||
|
||||
To setup a form for editing, you can bind a document by calling the `use` method.
|
||||
|
||||
```js
|
||||
edit_page.on('show', async (params) => {
|
||||
let doc = await frappe.get_doc('ToDo', params.name);
|
||||
edit_page.form.use(doc);
|
||||
})
|
||||
```
|
||||
|
||||
## New Document
|
||||
|
||||
To setup a form for a new document, just create a new document with the Frappe.js document helpers, and `use` it with paramter `is_new` = true
|
||||
|
||||
```js
|
||||
// setup todo new
|
||||
frappe.router.add('new/todo', async (params) => {
|
||||
|
||||
// new document
|
||||
app.doc = await frappe.get_doc({doctype: 'ToDo'});
|
||||
|
||||
// set a random name
|
||||
app.doc.set_name();
|
||||
|
||||
// show the page
|
||||
app.edit_page.show();
|
||||
|
||||
// is_new=true
|
||||
app.edit_page.form.use(app.doc, true);
|
||||
});
|
||||
|
||||
```
|
32
frappe/docs/lists.md
Normal file
32
frappe/docs/lists.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Lists
|
||||
|
||||
A list object handles object listing and paging, for a standard model.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const Page = require('frappe-core/frappe/client/view/page').Page;
|
||||
const ListView = require('frappe-core/frappe/client/view/list').ListView;
|
||||
|
||||
// create a new page
|
||||
let todo_list = new Page('ToDo List');
|
||||
|
||||
// init a new list
|
||||
todo_list.list = new ListView({
|
||||
doctype: 'ToDo',
|
||||
parent: this.todo_list.body
|
||||
});
|
||||
|
||||
todo_list.on('show', () => {
|
||||
// refresh on show
|
||||
todo_list.list.run();
|
||||
})
|
||||
```
|
||||
|
||||
## Creating a new List
|
||||
|
||||
You can create a new list object by passing the `DocType` and the parent element of the list
|
||||
|
||||
## Refreshing
|
||||
|
||||
To reload the list, call the `run` method
|
12
frappe/docs/metadata.md
Normal file
12
frappe/docs/metadata.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Metadata
|
||||
|
||||
Metadata are first class objects in Frappe.js. You can get a metadata object by `frappe.get_meta`. All objects from the `models` folders of all modules are loaded.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
let todo_meta = frappe.get_meta('ToDo');
|
||||
|
||||
// get all fields of type "Data"
|
||||
let data_fields = todo_meta.fields.map(d => d.fieldtype=='Data' ? d : null);
|
||||
```
|
41
frappe/docs/models.md
Normal file
41
frappe/docs/models.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Declaring Models
|
||||
|
||||
Models are declared by adding a `.json` model file in the `models/doctype` folder of the module/app.
|
||||
|
||||
Note: A model is called `DocType` in Frappe.js
|
||||
|
||||
### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"autoname": "hash",
|
||||
"name": "ToDo",
|
||||
"doctype": "DocType",
|
||||
"issingle": 0,
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "subject",
|
||||
"label": "Subject",
|
||||
"fieldtype": "Data",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"label": "Description",
|
||||
"fieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"label": "Status",
|
||||
"fieldtype": "Select",
|
||||
"options": [
|
||||
"Open",
|
||||
"Closed"
|
||||
],
|
||||
"default": "Open",
|
||||
"reqd": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
41
frappe/docs/page.md
Normal file
41
frappe/docs/page.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Page
|
||||
|
||||
A page is a basic container that fills up the `main` area of the Frappe.js SPA.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const Page = require('frappe-core/frappe/client/view/page').Page;
|
||||
|
||||
let todo_list = new Page('ToDo List');
|
||||
|
||||
// make the current page active
|
||||
todo_list.show();
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
The page has the following elements
|
||||
|
||||
1. Body
|
||||
|
||||
## Events
|
||||
|
||||
You can `show` a page or `hide` a page.
|
||||
|
||||
## Bind Events
|
||||
|
||||
- `show` when a page is shown
|
||||
- `hide` when a page is hidden
|
||||
|
||||
```js
|
||||
let todo_list = new Page('ToDo List');
|
||||
|
||||
// run the refresh when it is shown
|
||||
todo_list.on('show', () => todo_list.list.run());
|
||||
```
|
||||
|
||||
|
||||
## Current Page
|
||||
|
||||
The current page is maintained in `frappe.router.current_page` and is set the the lastest shown page.
|
79
frappe/docs/rest.md
Normal file
79
frappe/docs/rest.md
Normal file
@ -0,0 +1,79 @@
|
||||
# REST API
|
||||
|
||||
You can directly access documents at `/api/resource/:doctype`
|
||||
|
||||
### Create
|
||||
|
||||
- URL: `/api/resource/:doctype`
|
||||
- Method: `POST`
|
||||
- Data: document properties
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo`
|
||||
- Method: `POST`
|
||||
|
||||
Data:
|
||||
|
||||
```json
|
||||
{
|
||||
"subject": "test",
|
||||
"description": "test description"
|
||||
}
|
||||
```
|
||||
|
||||
### Read
|
||||
|
||||
- URL: `/api/resource/:doctype/:name`
|
||||
- Method: `GET`
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo/uig7d1v12`
|
||||
|
||||
Reponse:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "uig7d1v12",
|
||||
"owner": "guest",
|
||||
"modified_by": "guest",
|
||||
"creation": "2018-01-01T12:08:19.482Z",
|
||||
"modified": "2018-01-01T12:08:19.482Z",
|
||||
"docstatus": 0,
|
||||
"subject": "test 1",
|
||||
"description": "description 1",
|
||||
"status": "Open"
|
||||
}
|
||||
```
|
||||
|
||||
### List
|
||||
|
||||
- URL: `/api/resource/:doctype/`
|
||||
- Method: `GET`
|
||||
- Params (optional)
|
||||
- `start`: Page start
|
||||
- `limit`: Page limit
|
||||
|
||||
**Example:**
|
||||
|
||||
- URL: `/api/resource/todo`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "r4qxyki0i6",
|
||||
"subject": "test 1"
|
||||
},
|
||||
{
|
||||
"name": "efywwvtwcp",
|
||||
"subject": "test 1"
|
||||
},
|
||||
{
|
||||
"name": "9ioz05urgp",
|
||||
"subject": "test 1"
|
||||
}
|
||||
]
|
||||
```
|
52
frappe/docs/router.md
Normal file
52
frappe/docs/router.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Client-side Routing
|
||||
|
||||
The Frappe.js client comes in with a built in router, that is handles via hashing (example `#route`)
|
||||
|
||||
## Add a new route
|
||||
|
||||
You can add a new route by calling `frappe.router.add`
|
||||
|
||||
Dynamic routes can be added by declaring each parameter as `:param` in the route string (similar to express.js)
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const Page = require('frappe-core/frappe/client/view/page').Page;
|
||||
|
||||
let todo_list = new Page('ToDo List');
|
||||
|
||||
// make the current page active
|
||||
todo_list.show();
|
||||
```
|
||||
|
||||
|
||||
```js
|
||||
// to do list
|
||||
frappe.router.add('default', () => {
|
||||
app.todo_list.show();
|
||||
app.todo_list.list.run();
|
||||
});
|
||||
|
||||
// setup todo form
|
||||
frappe.router.add('edit/todo/:name', async (params) => {
|
||||
app.doc = await frappe.get_doc('ToDo', params.name);
|
||||
app.edit_page.show();
|
||||
app.edit_page.form.use(app.doc);
|
||||
});
|
||||
|
||||
// setup todo new
|
||||
frappe.router.add('new/todo', async (params) => {
|
||||
app.doc = await frappe.get_doc({doctype: 'ToDo'});
|
||||
app.doc.set_name();
|
||||
app.edit_page.show();
|
||||
app.edit_page.form.use(app.doc, true);
|
||||
});
|
||||
```
|
||||
|
||||
## Show a route
|
||||
|
||||
To set a route, you can call `frappe.router.show(route_name)`
|
||||
|
||||
```js
|
||||
frappe.router.show(window.location.hash);
|
||||
```
|
20
frappe/docs/server.md
Normal file
20
frappe/docs/server.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Server
|
||||
|
||||
The framework comes bundles with an `express.js` web server with pre-built backends, [REST API](rest.md) and ORM.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const server = require('frappe-core/frappe/server');
|
||||
|
||||
server.start({
|
||||
backend: 'sqllite',
|
||||
connection_params: {db_path: 'test.db'},
|
||||
static: './',
|
||||
port: 8000
|
||||
});
|
||||
```
|
||||
|
||||
By starting a server, Frappe will automatically handle REST calls for all the declared models.
|
||||
|
||||
Database migration (syncing the tables based on models) is also done at the time of server start.
|
9
frappe/docs/testing.md
Normal file
9
frappe/docs/testing.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Tests
|
||||
|
||||
All tests are in the `tests` folder and are run using `mocha`. To run tests
|
||||
|
||||
### Calling
|
||||
|
||||
```sh
|
||||
npm run test
|
||||
```
|
Loading…
Reference in New Issue
Block a user