🚧 Work in progress
A bunch of general purpose and UI5 focused functional helpers to be used within SAPUI5 and non-SAPUI5 environment.
It can be easily imported just like the utilities.js
file on controllers.
All functions are curried, meaning that if the calling function was not provided with all the required arguments, it will return another function that expects the remaining arguments. The function itself will be called when all the arguments are fulfilled.
So you can leverage the power of partial application within sapui5 models.
Please, refer to the example repo Functional-UI5-Example where you can see a Todo webapp with this lib implementation.
Given a parent p, returns model handler functions bound to the provided parent.
parent examples:
- View
- Component
- Fragment
Usage
models.js
return {
handler: undefined,
// called from Component.js
init: function (comp) {
this.handler = L.model(comp)
console.log(this.handler)
/**
* Outputs: Functions to handle models
* {
* applyTo: fn,
* assignTo: fn,
* compose: fn,
* filter: fn,
* for: fn,
* getData: fn,
* getModel: fn,
* getModelPromise: fn,
* map: fn,
* pick: fn,
* pipe: fn,
* prop: fn,
* pushTo: fn,
* reduce: fn,
* setData: fn,
* setModel: fn
* }
*/
},
}
Given a model name s and any data, sets model with the given name and data into the model handler provider. Returns the set model.
Usage
models.js
return {
// called from Component.js. The Component instance is passed as a parameter using 'this' keyword
init: function (comp) {
this.handler = L.model(comp)
this.handler.setModel('Todos', []) // saves list of todos
this.handler.setModel('Todo', {}) // saves data for new todos
// All models are set to the Component when using 'this.handler', since the component was passed as an argument of L.model function.
const Todos = comp.getModel('Todos')
console.log(Todos.getData())
/**
* Outputs: []
*/
},
}
Given a model name s, gets model with the given name from the provided parent.
Usage
Todo.controller.js
return {
addTodo: function () {
const Todos = models.handler.getModel('Todos')
const todos = L.clone(Todos.getData())
const Todo = models.handler.getModel('Todo')
const todo = Todo.getData()
todos.push({
id: 1,
description: todo.description,
checked: false,
})
console.log(todos)
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s and any data, sets data onto the given model name inside the model handler provider. Returns the set data.
Usage
Todo.controller.js
return {
addTodo: function () {
const Todos = models.handler.getModel('Todos')
const todos = L.clone(Todos.getData())
const Todo = models.handler.getModel('Todo')
const todo = Todo.getData()
todos.push({
id: 1,
description: todo.description,
checked: false,
})
models.handler.setData('Todos', todos)
console.log(Todos.getData())
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s, fetches data from the given model name inside the model handler provider. This function does not return a reference, it returns a copy of the data.
Usage
Todo.controller.js
return {
addTodo: function () {
const todos = models.handler.getData('Todos')
const todo = models.handler.getData('Todo')
todos.push({
id: 1,
description: todo.description,
checked: false,
})
models.handler.setData('Todos', todos)
console.log(models.handler.getData('Todos'))
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s and an object, assign the provided object to the model data. Returns the assign result.
*can also be used as an update method, since it replaces props if them already exist
Usage
Todo.controller.js
return {
addTodo: function () {
const Todo = models.handler.getModel('Todo')
const todos = models.handler.getData('Todo')
const todo = models.handler.getData('Todo')
todos.push({
id: 1,
description: todo.description,
checked: false,
})
models.handler.setData('Todos', todos)
console.log(Todo.getData())
/**
* Outputs: { description: 'Do something' }
*/
models.handler.assignTo('Todo', {
description: '',
newProp: 'Hello',
})
console.log(Todo.getData())
/**
* Outputs: { description: '', newProp: 'Hello' }
*/
},
}
Given a model name s and any data, push the data to the model. Returns the push result.
Usage
Todo.controller.js
return {
addTodo: function () {
const todo = models.handler.getData('Todo')
models.handler.pushTo('Todos', {
id: 1,
description: todo.description,
checked: false,
})
console.log(models.handler.getData('Todos'))
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s and a function, apply the function to the given model data. Returns the apply result.
Usage
models.js
let component
return {
init: function (comp) {
component = comp
},
getHandler: function () {
return L.model(component)
},
sendTodosToDB: todos =>
new Promise(res => {
setTimeout(() => {
res({
status: 201,
payload: JSON.stringify(todos),
})
}, 2000)
}),
}
Todo.controller.js
return {
id: 0,
init: function () {
const handler = models.getHandler()
handler.setModel('Todos', [
{
id: 0,
description: 'Hello Todo!',
checked: false,
},
])
},
sendTodos: function () {
models.Todos.applyTo(models.sendTodosToDB).then(console.log)
/**
Outputs: {
"status": 201,
"payload": [{
"id": 0,
"description": "Hello Todo!",
"checked": false
}]
}
*/
},
}
Given a model name s, return the equivalent of L.model, but with the model name bound to it. It creates the model if it doesn't exist, whose data will default to an empty object: { }
This allows you to use every single function for model handling. Please, refer to L.model function at the top to see what functions are available.
Note¹: for() won't be included as a result of calling for(), since it has no purpose of using it in this occasion
Note²: getModelPromise() won't be include as a result of calling for(), since the model is created when using for(), making getModelPromise useless in that case
Usage
models.js
return {
Todos: undefined,
Todo: undefined,
// called from Component.js. The Component instance is passed as a parameter using 'this' keyword
init: function (comp) {
this.Todos = L.model(comp).for('Todos')
this.Todo = L.model(comp).for('Todo')
this.Todos.setData([])
},
}
Todo.controller.js
return {
addTodo: function () {
const { description } = models.Todo.getData()
models.Todos.pushTo({
id: 1,
description: description,
checked: false,
})
console.log(models.Todos.getData())
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s and a prop name, return the prop from the model data. Can be used with objects and arrays. When using with arrays it will map through the array fetching the prop.
Usage
Todo.controller.js
return {
addTodo: function () {
const description = models.Todo.prop('description')
models.Todos.pushTo({
id: 1,
description,
checked: false,
})
console.log(models.Todos.getData())
/**
* Outputs: [{
* id: 1
* description: 'Do something',
* checked: false
* }]
*/
},
}
Given a model name s and an array of n props names, return the props from the model data. Can be used with objects and arrays. When using with arrays it will map through the array fetching the props.
Usage
Todo.controller.js
return {
addTodo: function () {
const description = models.Todo.prop('description')
models.Todos.pushTo({
id: 1,
description,
checked: false,
})
models.Todos.pushTo({
id: 2,
description,
checked: true,
})
const data = models.Todos.pick(['id', 'checked'])
console.log(data)
/**
* Outputs: [{
* id: 1,
* checked: false
* },
* {
* id: 2,
* checked: true
* }]
*/
},
}
Given a model name s and a function, filter the model s with the passed function. Returns data filtered with the function.
Usage
Todo.controller.js
return {
addTodo: function () {
const description = models.Todo.prop('description')
models.Todos.pushTo({
id: 1,
description,
checked: false,
})
models.Todos.pushTo({
id: 2,
description,
checked: true,
})
const getCompletedOnly = todo => todo.checked
/**
* Could be:
* const getCompletedOnly = L.prop('checked')
*/
const data = models.Todos.filter(getCompletedOnly)
console.log(data)
/**
* Outputs: [{
* id: 2,
* checked: true
* }]
*/
},
}
Given a model name s and a function, map through the model s with the passed function. Returns data mapped with the function.
Usage
Todo.controller.js
return {
addTodo: function () {
const description = models.Todo.prop('description')
models.Todos.pushTo({
id: 1,
description,
checked: false,
})
models.Todos.pushTo({
id: 2,
description: 'My Description',
checked: true,
})
const getDescriptions = todo => todo.description
/**
* Could be:
* const getDescriptions = L.prop('description')
*/
const data = models.Todos.map(getDescriptions)
console.log(data)
/**
* Outputs: ['Do something', 'My Description']
*/
},
}
Given a model name s, a function and an initial value b, reduce through the model s with the passed function using the initial value as the starting accumulator. Returns data reduced with the function.
Usage
Todo.controller.js
return {
addTodo: function () {
const description = models.Todo.prop('description')
models.Todos.pushTo({
id: 1,
description,
checked: false,
})
models.Todos.pushTo({
id: 2,
description: 'My Description',
checked: true,
})
// There are better ways of doing it, this is just for demonstration purposes
const checkIfAllCompleted = (result, todo) => result && todo.checked
const result = models.Todos.reduce(checkIfAllCompleted, true)
console.log(result)
/**
* Outputs: false
*/
},
}
Given a model name s, return a promise to the given model, which resolves with the model data whenever the model is set.
Usage
models.js
let component
return {
init: function (comp) {
component = comp
},
getHandler: function () {
return L.model(component)
},
getTodosFromAPI: () =>
new Promise(res => {
setTimeout(() => {
res([
{
id: 0,
description: 'Do something with this data',
checked: false,
},
])
}, 2000)
}),
}
Todo.controller.js
return {
onInit: function () {
const handler = models.getHandler()
const setTodosToModels = () => {
models.Todos = handler.for('Todos')
}
// Although the model isn't set, it won't throw an error
handler
.getModelPromise('Todos')
.then(console.log) // Outputs: [{ id: 0, description: 'Do something with this data', checked: false }]
.finally(setTodosToModels)
models.getTodosFromAPI().then(handler.setModel('Todos')) // Here the model is set
},
}