GithubHelp home page GithubHelp logo

arturadib / agility Goto Github PK

View Code? Open in Web Editor NEW
543.0 543.0 71.0 3.79 MB

Javascript MVC for the "write less, do more" programmer

Home Page: http://agilityjs.com

License: MIT License

JavaScript 86.58% HTML 11.94% CSS 1.48%

agility's People

Contributors

arturadib avatar pindia avatar quartzo avatar robertjustjones avatar tristanls avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

agility's Issues

Add input type="search" support to data-bind, make it tight

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.

Radio with different parents

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);

can't put empty string on a 'div' with 'data-bind'

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('');
                 }
               });
             }

Agility and Raphael don't like each other....

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.

$node.prop is not a function

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>


2-in-1 for input data-bind

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!

Add-remove implementation

Upon object.add():

  • Add element to tree
  • Subscribe to remove (i.e. implement removeChild), which will remove the given child from the tree

Upon object.remove():

  • Call this.view.remove(), which will remove the DOM element
  • Trigger event remove, which will be captured by parent

Original model not updated

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.

Feature Request: Event after model is ready

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() {
                  ...
                                  ...
              } 
            }

Implemented full hierarchical inheritance of any controller event

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>

Support comma-separated events in controller bindings

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).

Establish standards for controller methods/events

  • All controller methods/events should begin with caller, e.g. treeAdd(), modelChange(), etc, except for DOM events;
  • Controller events are called after implementation of function in original component, e.g. .tree.add() should .trigger('treeAdd') after adding new child

JSHINT is not defined ( when running core_only.html test )

Steps to duplicate:

  1. follow instructions in test/README.md by pointing browser to http://localhost/agility/test/core_only.html

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" }

Incorrect data-bind string format breaks in very cryptic way

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">

Consistent terminology: create/destroy, add/remove, init/?

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.

Allow HTML templates/jQuery selectors in view

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.

Set/Get out of order for keydown event

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.

submit event for forms does not fire

I can't seem to setup an event listener for the submit event on a form. See example below...

var searchbar = $$({
model:{},
view:{
format:
'




',
style:
'& input[type="search"] {width:70%;}
& input[type="submit"] {width: 10%;}'
},
controller:{
'submit form': function(){
alert(16);
}
}
});
$$.document.append(searchbar);

Insert agility object anywhere on the DOM

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.

Data bindings don't seem to work when element attributes are hyphenated

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!

can't update DOM

Hello,

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

  • element in the console!

        '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!

  • Problem Persisting Objects

    The following bit of code extends your people example and attempts to add a new person by using $$(person) to extend the object and create new instances of the object. It seems I need to call persist each time or I get the error below. Either I am doing wrong (most likely) or there is a bug in the $$ method?

    Error

    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
    

    Code

    (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);
    })();
    

    destroy() does not propagate through children

    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.

    when I use '&' before Css selector,but the string is still black

    I 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>

    Revisiting differential inheritance - extend by default?

    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:

    • Pros: More compact syntax for desired behavior
    • Cons: Non-uniform behavior, that is, models and formats are treated differently from styles and controllers

    What do you think?

    model.set: Fix modified fields when reset=true

    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
    

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google โค๏ธ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.