Gilgamesh is a collection of useful plugins and extensions of AngularJS( Polymer version is coming soon) to help you build modern web application. Run a local web server and browse to http://127.0.0.1/index.html to get start or checkout the online demo.
D("user").get() //get user list
D("user").get({name:"Gilgamesh"}) //get user list with parameters
//id can be replace by any name you defined as primary key
D("user").get({id:1})
D("user").get(1)
var newUser = D("user").new()
newUser.name = "me"
newUser.save()
D("user").get(id).publish("global.user")
D("user").receive("global.user")
$$filled //is data filled from ajax data
$$valid //need method validate implemented
$$dirty //is data changed?
$$empty //is data equal to undefined, null, or "".
$$validating
$$validated
$$saving
$$saved
$$actions //map of current action status. example: {"saving":false,"saved":"true","deleting":true}
.validate() //need to be validate manually
.delete()
.save()
.watch("attribute", callback) //watch certain attribute
.watch(callback) //watch object
.notify() //manualy call watch callbacks
Actions will generate PUT
http request with url "/{id}/{action}". Example:
D("user").get(id).action("doSomething")({/*parameters*/})
Batch Actions example:
D("user").get({name:"Gilgamesh"}.action("batchAction")(params).
D("user").get({name:"Gilgamesh"}.filter("id",[ids]).action("batchAction")(params).
//or you can use it via DataSource directly. The difference is that actions on
//collection will change the status of current collection.
D("user").action("batchAction")(params)
D("user").action("doSomething",function( instanceOrCollections, params, dataSource ){
//return setting to overwrite default ajax settings
return {
url : "/url",
method : "POST",
data : {}
success : function( res ){
dataSource.parse(res)
}
}
})
<div gm-data="D('user').get(1) as user">
name : <input type="text" ng-model="user.name">
gender : <input type="text" ng-model="user.gender">
<button ng-click="user.save()">save</button>
</div>
First, use component
instead of directive
:
.component("userCardForm", function(){
return {
//require : "gmSource",
priority : 98,
template:
' <div gm-role="input">'+
' <input type="text" ng-model="user.name">'+
' <input type="text" ng-model="user.gender">'+
' </div>'+
' <button gm-role="save" ng-click="user.save()">save</button>'
link : function( $scope, $el, $attrs){
console.log("watch $$saved")
$scope.user.watch("$$saved", function( saved ){
if( saved ){
try{
if($el.attr('onSubmit') ) (new Function( $el.attr('onSubmit')))()
console.log( $el.attr('onSubmit'))
console.log( "on submit", saved)
}catch(e){
console.log( e )
}
}
})
}
}
})
Secondly, overwrite template with child element:
<div user-card-form gm-data="D('user').new() as user">
name : <input type="text" ng-model="user.name">
gender : <input type="text" ng-model="user.gender">
<button role="save" ng-click="user.save()">save</button>
<div>saving : {{user.$$saving}}</div>
<div>saved : {{user.$$saved}}</div>
</div>
As you may notice that a extra attribute gm-role
was added to child element of directive user-card-form
. We can do partial overwriting with gm-tpl
set to include
:
<div user-card-form gm-tpl-include gm-data="D('user').new() as user" >
<button role="save" ng-click="user.save()">only changed button</button>
</div>
What if you only want to exclude certain part? For instance, We can exlude the save button like:
<div user-card-form gm-tpl-exclude="save" gm-data="D('user').new() as user" ></div>
Magic here, We can break the fence of html structure. Surpose we need to place the save button outside the user-card-form
due to some insane reason, we simply do:
<button gm-import="newUser" gm-role="save">save from outside</button>
<div id="newUser" user-card-form gm-data="D('user').new() as user" ></div>
gm-import
is used to specify the id of which element you want to import from, and gm-role
is used to identify the import part.
In some cases interaction between directives requires a lot of api or event, and sharing scope would make it much easier. We cant still use gm-import
to do that.
<div gm-import="newUser">{{user.name}}</div>
<div id="newUser" user-card-form gm-data="D('user').new() as user" ></div>
Extending a exist component is easy:
.component("userCardForm", function(){
return {
extend : "otherComponent",
link : function( $scope, $el, $attrs){
//parent link function will apply first
}
}
})
Waht happend in the background is that parent component link function will apply on the same scope and element. So public method or event listenner will be inherited.
//HTML markup
<user-card-form on-submit="user.save()"></user-card-form>
.component("userCardForm", function(){
return {
link : function( $scope, $el, $attrs){
var e = new Event("submit")
$el[0].dipatchEvent(e)
}
}
})
Api should be exposed on element.
We provided various ways like role-based element import for cases require scope or method sharing, please use it instead of lifting angular scope.
As title says, for example, implementing attribute onSubmit
on a custom form would be the right way to invoke callback.
Directives
.component( "myModal", function(){
return {
link : function( $scope, $el, $attrs ){
$el.css({/*your modal css*/})
$el[0].open = function(){
$el.show()
}
$el[0].hide = function(){
console.log("closing")
$el.hide()
}
$el.hide()
}
}
})
.component("userCardForm", function(){
return {
template:
'<div role="input">'+
' <input type="text" ng-model="user.name">'+
' <input type="text" ng-model="user.gender">'+
'</div>'+
'<button role="save" ng-click="user.save()">save</button>',
link : function( $scope, $el, $attrs){
$scope.user.watch("$$saved", function( saved ){
saved && $el.attr('onSubmit') ) && (new Function( $el.attr('onSubmit')))()
})
}
}
})
HTML
<button onClick="el('ecs-create-modal').open()">open modal</button>
<my-modal id="ecs-create-modal">
<modal-body>
<div id="userCard" gm-source="D('user').new() as user" gm-tpl-exclude="save" onSubmit="el('ecs-create-modal').hide()"></div>
</modal-body>
<modal-foot>
<button gm-import="userCard" gm-role="save">save</button>
</modal-foot>
</my-modal>
- Polymer support
- React support
- Event system