arturadib / agility Goto Github PK
View Code? Open in Web Editor NEWJavascript MVC for the "write less, do more" programmer
Home Page: http://agilityjs.com
License: MIT License
Javascript MVC for the "write less, do more" programmer
Home Page: http://agilityjs.com
License: MIT License
Tight means the model is updated upon every keystroke. This is particularly useful in the context of instant searches.
var obj = $$({query:''}, '<input type="search" data-bind="query"/>', {
'change:query': function(){
... do search here ...
}
});
For regular searches, the user will need to capture the enter key, and/or a click on a button.
This shortcut might incentivize people to mess with the object internals, rather than use the appropriate object.view.*
methods.
Hi,
I was trying to use agility to set a radio checked in a set of radios in different parents, but it doesn't work because the use of siblings function on line 543 of agility.js. So I was wondering if there is any reason to not accept radios with different parents.
I'm using the example above, where the option "a" is not checked on start:
var obj = $$(
{opt:'opt-a'},
"<div> \
<ul> \
<li> \
<input type='radio' name='test' value='opt-a' data-bind='opt'>a</input> \
</li> \
<li> \
<input type='radio' name='test' value='opt-b' data-bind='opt'>b</input> \
</li> \
</ul> \
You selected: <span data-bind='opt'/> \
</div>"
);
$$.document.append(obj);
This code doesn't change the DOM:
// Bind model to element's HTML content
var message = $$({txt:"I'm text from a model"}, '<div data-bind="txt"/>');
$$.document.append(message);
message.model.set({'txt':''});
Simplest correction:
@@ -582,7 +582,7 @@
if (self.model.get(bindData.key)) {
$node.text(self.model.get(bindData.key).toString());
} else {
- $node.text( null );
+ $node.text('');
}
});
}
The parser is repeating itself in bind()
and trigger()
. Put all of that into a common, perhaps util.*
function.
I'm not sure if this is a problem with Agility or Raphael or it's just that "Javascript - DOM" programming sucks. Here's the scenario:
1- I have Agility object A.
2- object A contains a div with id='r'
3- on 'create', object A creates a Raphael object by feeding Raphael with this.view.$('#r')[0]. Raphael creates an object and gives it a transparent gradient.
4- object A is added to the document by $$.document.append(A)
Result: the gradient is not shown.
Why: Raphael creates the gradient objects in the window.document, not in $$.document which lives in memory.
Workaround: create the Raphael object after step 4, not at step 3. this way, every agility object will already live in the DOM.
Hello, I am trying each one of the examples in http://agilityjs.com/docs/docs.html in my own server.
all is fine except the examples
** // Two-way input binding (radio)
and
** // Two-way input binding (select)
I get the following error:
$node.prop is not a function
http://localhost/agility/js/lib/agility.js
Line 507
Is a bug, or the example is incomplete.
Ill appreciate your help.
bellow is the code I have for "// Two-way input binding (select)"
<!DOCTYPE html> <html><head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Agility</title><script src="js/lib/jquery-1.5.2.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/lib/agility.js" type="text/javascript" charset="utf-8"></script>
</head><body>
<script type="text/javascript">
// Two-way input binding (checkbox)
var obj = $$(
{a:false, b:true},
"<div> </span>
<input type='checkbox' name='test' data-bind='a'/> checked: <span data-bind='a'/><br/> </span>
<input type='checkbox' name='test' data-bind='b'/> checked: <span data-bind='b'/><br/> </span>
</div>"
);
$$.document.append(obj);
</script>
</body></html>
Feature request #1
: If type isn't present on input element, default to type="text"
Feature request #2
: Instant data binding should't be bound to only type="search", but accessible on other types too!
Upon object.add()
:
tree
remove
(i.e. implement removeChild
), which will remove the given child from the treeUpon object.remove()
:
this.view.remove()
, which will remove the DOM elementremove
, which will be captured by parentThis is consistent with the persist plugin (persist:start
, persist:collect:start
, etc)
I would like agility to update the original model object I give to the factory function '$$()'.
This helps especially with big trees of agility components (e.g. Tables with hundreds of components).
I would like to have only one source of truth for the model.
I made a patch that takes the original model object instead of doing '$.extend(...)' and and throws an exception if the new model is non-empty and the model inherited from the prototype is non-empty too.
This works great for me and should save some memory at runtime.
Of course this behaviour is undesired for views and controllers.
Here is my Test-HTML:
var globalModel = { value: 'bla' };
var input = $$(globalModel,
'<div><input type="text" data-bind="value" /> value: <span data-bind="value" /></div>', {
'create': function() {
// put the original value somwhere visible
$('#message').append(globalModel.value);
},
'change:value': function() {
// put the original value again
$('#message').empty().append(globalModel.value);
// show the original value and the value from this.model
alert('global value: ' + globalModel.value + ', input.value: ' + this.model.get('value'));
}
}
);
$$.document.append(input, '#form');
Of course I would be willing to provide my patch (its quite small with two additional util functions).
But of course I am unsure if you like such a thing at all.
But for me its a plain bug since the view isn't bound to the model I provided.
When the "create" event is fired the model seems to be not accessible yet. Some sort of "afterCreate" event would be useful in some cases.
I worked around this using a jQuery callback:
// [...]
controller:
{ 'create': function() {
//model not ready yet
//trigger jQuery-Callback $(...) when ready
that = this;
$(function() { that.trigger('change'); });
},
'change': function() {
...
...
}
}
Backbone uses an argument to .fetch()
to specify page:
http://documentcloud.github.com/backbone/#Collection-fetch
Should we do the same?
Because pull request #34 is still pending and I don't want to overwhelm the review process I'm holding off on submitting this feature till #34 is resolved. But you can look at the code on my fork https://github.com/tristanls/agility
This future pull request implements hierarchical inheritance of controller events. It allows us greater reuse of agility objects and enables construction by composition. Here's what that means:
var label = $$( {}, '<span data-bind="label"/>' );
var labeledElement = $$( {}, '<div/>', {
'create': function() {
var lbl = $$( label, { label: this.model.get( 'label' ) } );
this.append( lbl );
}
});
var labeledValue = $$( labeledElement, {
controller: {
'extend:create': function() { // <- notice the 'extend:' syntax, this is *hint* to the framework to extend instead of overriding
var value = $$( label, { label: this.model.get( 'value' ) } );
this.append( value );
}
}
});
var myLabeledValue = $$( labeledValue, { label: "myLabel", value: "myValue" } );
<div><span data-bind="label">myLabel</span><span data-bind="label">myValue</span></div>
Basically it'd be nice to do many-to-one bindings like:
controller:{
'click button#save1, click button#save2': function(){}
}
A simple implementation without much code restructuring is to parse the controller name and clone the controller function multiple times, each with a new name corresponding to each event.
To save memory make them all point to the same function (perhaps in a closure).
treeAdd()
, modelChange()
, etc, except for DOM events;.tree.add()
should .trigger('treeAdd')
after adding new childSo that two Agility objects essentially share the same model. This enables multiple views per model.
By popular request. That seems to be the first thing that people want to know...
Steps to duplicate:
error:
JSHint: JSHint (1, 0, 1)Rerun
Died on test #1: JSHINT is not defined - { "arguments": [ "JSHINT" ], "type": "not_defined", "message": "JSHINT is not defined", "stack": "ReferenceError: JSHINT is not defined at Object. (file:///Users/seed/github/agility/test/public/core.js:13:18) at Object.run (file:///Users/seed/github/agility/test/public/qunit.js:104:18) at file:///Users/seed/github/agility/test/public/qunit.js:234:10 at process (file:///Users/seed/github/agility/test/public/qunit.js:867:23) at file:///Users/seed/github/agility/test/public/qunit.js:410:5", "name": "ReferenceError" }
If someone writes
< select data-bind="id id, value" >
It will break with unhelpful Uncaught agility.js: unknown argument for getter
error message. It would be quite difficult to figure out that the correction is
< select data-bind="value, id id">
Not working
It seems wasteful to add all those methods (.load()
, .save()
, etc) if most objects are not persist
ed...
Perhaps .persist()
can add these methods upon initialization?
These were suggested by @clyfe:
Right now the controller is a bit messy. It calls create()
, but there is no destroy()
(there's remove()
instead).
BUT, replacing remove()
by destroy()
means that we will need to split the current remove()
into destroy + remove
- the former for self-destruction, the latter for tree object removal.
Don't pollute the <head>
with orphan <style>
tags!
Lots of folks prefer to keep their HTML separate from JS. We should support that, perhaps through jQuery templates.
Or, as per suggestion of @svieira, we can let view formats to be functions, and let users decide what templating framework they want to use.
Some RESTful servers don't necessarily follow our conventions (e.g. body contains JSON object with id variable id
, etc), so it might be useful to allow the user to manipulate that data before sending it to the server and/or updating the model.
Maybe I'm doing it wrong, but some events fire before set is fired and some fire after.
var ist = $$({}, '<div><input type="text" data-bind="newContent" /><ul></ul></div>', {
'keydown input': function(e){
if (e.keyCode != 13) return; //if any key other than enter hit
//will return undefined
console.log( this.model.get('newContent') );
},
'change':function(e){
//will return the value of the input
console.log( this.model.get('newContent') );
}
});
And the problem with using change as the event is that it fires when the input loses focus if the value is different.
I can't seem to setup an event listener for the submit event on a form. See example below...
var searchbar = $$({
model:{},
view:{
format:
'
Feature is deprecated.
See e.g. setter in .model.set()
and factory function.
This might require cleaning up unit tests.
Now you can only insert an agility object at the beginning (prepend) or at the end (append) of the list of the children defined for a DOM object.
$$.document.prepend(agilityObj, "table");
or
$$.document.append(agilityObj, "table");
I need to put the agility object in the middle, after the "tr" that defines the header of the table and before the "tr" that show totals of the table.
I've been testing Agility.js with SVG. Data bindings don't seem to work for element attributes that have a hyphen in them.
The following works for stroke-width, giving the circle a stroke width of 10:
var obj = $$(
{
radius: 200,
centerx: 300,
centery: 300
},
' \
<svg> \
<circle stroke="black" fill="red" stroke-width="10" data-bind="r radius, cx centerx, cy centery" /> \
</svg> \
'
);
$$.document.append(obj);
But the following does not work for the stroke-width element attribute:
var obj = $$(
{
radius: 200,
centerx: 300,
centery: 300,
strokeWidth: 10
},
' \
<svg> \
<circle stroke="black" fill="red" data-bind="r radius, cx centerx, cy centery, stroke-width strokeWidth" /> \
</svg> \
'
);
$$.document.append(obj);
I hope this is helpful!
You asked for feedback :). These are requirements for me. I didn't see them in the docs.
_tree
contains .children
, add()
, remove()
, etcHello,
i've been looking into this for days and i can't get it to work, no matter what i try.
I have a Model that persists with CouchDB. Each instance contains a list of other documents, which i want to fetch
and display.
So, after i load the main model from the CouchDB (everything loads and displays fine) i have the following
called by the create event:
fill: function () {
for (i in this.model.get("pros")) { //model contains a list of couchdb IDs in the "pros" field
claim = $$(ClaimPro, {_id:this.model.get("pros")[i]});
claim = claim.load(); //this loads the document from couchdb, i can see the request going out
this.append(claim, "ul.pros"); //this appends the "ClaimPro" model to the <ul> element(browser displays the view without the actual data from CouchDB
}
This should load the Document from CouchDB and append it to the list.
I can see that it loads, because the template of "ClaimPro" displays multiple times on the webpage.
The Requests to CouchDB work fine, too, and when i put the following in the ClaimPro model i can see the correct
'persist:load:success': function() {
console.log(this.view.$root); //this outputs the view with the correct data from couchdb, but the browser shows only the template value
}
This outputs the correct format even with the value from CouchDB. Netherless the HTML in the Webbrowser isn't updated.
Why am i doing wrong?
thanks for help and best regards!
Map it to function returning object.view.$root.find(arg)
The following bit of code extends your people example and attempts to add a new person by using
Uncaught TypeError: Cannot read property 'adapter' of undefined
agility.fn.persist.save
e.extend.proxy.gjquery.js:16
$$.controller.click #add:53317/:51
e.extend.proxy.gjquery.js:16
Mjquery.js:16
f.event.handlejquery.js:17
f.event.add.i.handle.k
(function(){
var person = $$({}, '<li data-bind="name"/>').persist($$.adapter.restful, {collection:'people'});
var people = $$({
model: {},
view: {
format:
'<div>\
<span>Loading ...</span>\
<button id="load">Load people</button><br/><br/>\
<button id="add">Add Person</button><br/><br/>\
People: <ul/>\
</div>',
style:
'& {position:relative}\
& span {position:absolute; top:0; right:0; padding:3px 6px; background:red; color:white; display:none; }'
},
controller: {
'click #load': function(){
this.empty();
this.gather(person, 'append', 'ul');
},
'click #add': function(){
var p = $$(person, {name: "New Person"}).persist($$.adapter.restful, {collection:'people'});
p.save();
this.append(p, "ul");
},
'persist:start': function(){
this.view.$('span').show();
},
'persist:stop': function(){
this.view.$('span').hide();
}
}
}).persist();
$$.document.append(people);
})();
Someone claims to have a working IE8 shim for Object.watch()
:
http://stackoverflow.com/questions/1029241/javascript-object-watch-for-all-browsers
Not sure if that works on IE7... probably not.
Anyway, if that's an acceptable solution, we can get rid of the manual model setters/getters and simply use .model.property = "whatever"
.
Make it possible to do something like:
var obj = $$({path:'...', name:'...'}, <img data-bind="src path, title name" />);
Hey @arturadib, I noticed that the destroy event isn't propagated to the children, so if I have a hierarchy like so
var child = $$( );
var parent = $$( );
var grandparent = $$( );
grandparent.append( parent );
parent.append( child );
then when I call grandparent.destroy()
, the destroy
event is never triggered for the child
. Is there a specific design reason for this? I'm running into children not removing themselves as listeners, even though I thought they were being destroyed.
To clarify further, I have bound a pre:destroy
event inside child
to make sure it cleans up after itself in the application. But since destroy
isn't getting called, the cleanup doesn't happen.
*-post
, e.g. init-post
this.view.render()
and this.view.stylize()
in init()
within unit test and demo by whatever you need thereI just copy the code these code from doc,but it doesn't work! does I do something wrong?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Agility style-need-& </title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="agility.js" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript" charset="utf-8">
var obj = $$({}, '<p><div>Do this</div></p>', '& div { color:red; }');
$$.document.append(obj);
</script>
</body>
</html>
See Yahoo article http://yuiblog.com/blog/2007/06/07/style/
_events
contains .bind()
and .trigger()
For consistency
This debate has been sparked by the work of @tristanls, who implemented the extend (~
) syntax for controllers.
Originally, Agility tried to stick to a differential inheritance paradigm. This meant that all properties of Agility objects were passed on to their descendants as prototype methods, except when overridden by the children:
// parent defines controller
var parent = $$({}, '<div/>', {
'create': function(){}
});
// child redefines controller of parent
var child = $$(parent, {}, {}, {
'create': function(){... new controller ...}
})
That was not the desired behavior, mainly because there would be no way to extend previously defined controllers. So @tristanls proposed the new syntax ~
for controllers, which would allow one to keep the previously defined handler create
, and add some more logic to it:
// child *extends* controller of parent
var child = $$(parent, {}, {}, {
'~create': function(){... more logic in addition to parent's...}
})
Then Darren Mason pointed out that a similar issue arises with CSS styles:
// parent defines style
var parent = $$({}, {format:'<div/>',
style:'& {color:red}'
});
// child redefines style, losing the color above
var child = $$({}, {format:'<div/>',
style:'& {float:right}'
});
Again, @tristanls proposed a similar solution:
// child *extends* style, keeping color from parent
var child = $$({}, {format:'<div/>',
'~style':'& {float:right}'
});
This seems to reveal a pattern - whenever some properties can be extended, it seems like the desired default behavior is to extend, and not override. This includes CSS styles and controllers. (There doesn't seem to exist a way to naturally extend models and formats, so these would have to be overridden by default).
So I am considering the possibility to make extend the default behavior for controllers and styles, and to introduce a new syntax !
to allow children objects to override inherited properties, e.g.
// parent defines style
var parent = $$({}, {format:'<div/>',
style:'& {color:red}'
});
// extend style (default behavior), keeping color above
var child = $$({}, {format:'<div/>',
style:'& {float:right}'
});
// redefine style, losing the color above
var child2 = $$({}, {format:'<div/>',
'!style':'& {float:right}'
});
The pros and cons I can see are:
What do you think?
Field should be handeled as modified and fire change:field
if it dissapeades in new data
obj.model.set({field: "hi"}, {reset: true});
obj.model.set({}, {reset: true}); // here `change:field` doesn't fire, but should
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.