Git Product home page Git Product logo

ripple's Introduction

ripple.js

Build Status

A tiny foundation for building reactive views with plugins. It aims to have a similar API to Reactive, but allow composition of views, like React. The major difference for other view libraries is that there are no globals used at all. Each view has its own set of bindings and plugins. This makes composition of views really easy.

var Person = ripple('<div>{{name}}</div>')
  .attr('name', { required: true, type: 'string' });

var person = new Person({
  name: 'Tom'
});

person.appendTo(document.body);
person.name = "Barry"; // DOM updates automatically

Install

component install ripplejs/ripple

Browser Support

Supports real browsers and IE9+.

Documentation

Documentation is on the wiki.

Examples

See more examples at ripplejs/examples

Plugins

  • shortcuts - add custom key binding combos
  • events - add event listeners to the DOM and call methods on the view
  • each - Basic iteration using the each directive.
  • bind-methods - Bind all methods on the prototype to the view
  • markdown - Adds a directive to render markdown using Marked.
  • extend - Makes adding methods to the view prototype a little cleaner
  • intervals - Easily add and remove intervals
  • computed - Add computed properties.
  • refs - Easily reference elements within the template
  • dispatch - Dispatch custom DOM events up the tree

View and add them on the wiki

License

MIT

ripple's People

Contributors

anthonyshort avatar chrisbuttery avatar matthewmueller avatar olivoil avatar shinnn avatar vendethiel 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ripple's Issues

content insertion

Is it possible to insert content into composed components like this?

<app-sidebar>
  <li>home</li>
  <li>profile</li>
</app-sidebar>

app-sidebar:

<div>
  <ul>
    <!-- content from component goes here -->
    <content></content>
  </ul>
<div>

This is how it's done with native web components. Is there a ripple way? Couldn't find anything in the documentation.

Bower

Perhaps, it's better to add bower for people who don't use component?

0.6.0 API changes

As part of the changes I'm making to the API for 0.6, I thought I'd talk about some of the goals and things I want to fix:

Extract the data-binding engine

This will allow me to finish of the virtual DOM engine. When creating a view you would need to choose a rendering engine for the view.

var bindings = binder(template)
  .use(someDirective)
  .use(someFiltersAndShit);

var View = ripple()
  .engine(bindings);

The syntax for this is still a little in progress, but the code behind it works, it's just a matter of making it feel nice in the API.

Less confusing API

At the moment, you need to listen to events on the class and possibly on the instance.

View.on('mounted', function(view){
  view.foo = bar;
});

View.prototype.submit = function() {
  this.foo = bar;
};

This is a little confusing having them next to each other but with a different syntax. Obviously one is an event and the other is a handler. There are a couple of examples of how this could work here: https://gist.github.com/anthonyshort/2dbf56c398f320a4db61

Option 1:

At the moment, I think this might be the nicest solution:

var View = ripple({
  initialize: function(){},
  mounted: function(){
    this.foo = bar;
  }, 
  submit: function(){
    this.foo = bar;
  }
});

View
  .use(binding(template))
  .attr('foo');

And if a key an event lifecycle name we'd add it as a callback automatically. This is a little too much magic possibly, but it does create a nice abstraction and allows all the methods to be in place.

Option 2

We use the ripple() function to create View that we inherit from:

var View = ripple()
  .engine(bindings)
  .attr('firstName')
  .attr('lastName');

View.on('initialize', function(view){
  view.foo = bar;
});

module.exports = View.extend({
  onClick: function(event){
    console.log('clicked!'); 
  }
});

Again, I think this confuses things because there are two different ways to add 'methods' and each has a different context. We'd also be using inheritance.

Option 3

Using a handler or method function to add methods so that it follows the same syntax as the events:

View.on('initialize', function(view){
  view.foo = bar;
});

View.handler('onClick', function(view, event){
  view.foo = bar;
});

Allow for ES6 modules and classes

If we used Option 1 above, it could possibly allow us to have a nice syntax for using ES6 classes. It's not necessary, but it would be nice.

import ripple from 'ripple';
import binder from 'binder';
import template from './template';

var bindings = binder()
  .use(someDirective)
  .use(someFiltersAndShit);

class View {
  constructor() {
    super();
    console.log('initializing a view!');
  },
  onClick(event) {
    console.log('clicked!');
  }
}

export ripple(View)
  .engine(bindings(template))
  .attr('firstName')
  .attr('lastName');

With an alternative syntax using extends

var Base = ripple()
  .engine(bindings(template))
  .attr('firstName')
  .attr('lastName');

exports class View extends Base {
  initialize() {
    console.log('initializing a view!');
  },
  onClick(event) {
    console.log('clicked!');
  }
}

Option 1, at the very least, would allow us to do this:

var View = ripple({
  mounted() {
    this.foo = bar;
  }, 
  submit() {
    this.foo = bar;
  }
});

error when passing down array of views

When passing down an array of objects that have reference to themselves (views have this through the owner/child relationship) it throws a stack overflow error.

  • Update ripplejs/path-observer to not use clone
  • Make views have no cyclical relationship

Event handlers to Views created with selectors

1. Creating view with selector

When I run the test suite the following test is running well:

  it('should create a view with a selector', function () {
    var test = document.createElement('div');
    test.id = 'foo';
    document.body.appendChild(test);
    View = ripple('#foo');
    var view = new View();
    assert(view.template = '<div id="foo"></div>');
  });

But in reality when I try to create a view with selector out of existing DOM it cuts out the wrapper. For example:

html -> <button id='myButton'>Save</button>

js -> var View = ripple('#myButton'); var viewInstance = new View()

I end up having viewInstance.template = 'Save'. I guess due to this code in getTemplate:

  if (typeof template.innerHTML === 'string') {
    template = template.innerHTML;
  }

2. View with selector + Event Handlers (events plugin)

What is the best practice of attaching event handlers to Views created with selectors?

Again:

html -> <button id='myButton' on-click="{{ this.save }}">Save</button>

js -> var View = ripple('#myButton'); ....

I found that I must do viewInstance.replace('#myButton') (probably to trigger mount event and make it work). And note that this is only going to work if I avoid the problem in 1. I put myButton in kind of wrapper - lets say:

<div id='d'><button id='myButton' on-click="{{ this.save }}">Save</button></div>

and then var View = ripple('#d');

Template Spec (or Documentation) is Unclear...

It seems that templates only work if they are composed of a single DOM element, even if it's a simple

...

This is not obvious in the documentation -- and templates without this minor wrapper element seem not to parse correctly beyond the first element.

It may be this is by design, but, if so - it's not obvious without inspecting all the examples, etc. :)

(no examples provided, but take any of the standard examples, and remove the outer wrapper element... ๐Ÿ‘Ž )

-Dx

Cant bind functions to iteration items

I was trying to implement a simple list, based on the samples provided.

The following JS:

listTemplate = "<div class=\"ItemsList\">\n  <ul each=\"{{items}}\">\n    <li>\n      {{name}} <button on-click=\"{{ this.removeItem.bind(this, $index) }}\">Remove</button>\n    </li>\n  </ul>\n</div>";

List = ripple(listTemplate).use(each);

List.prototype.removeItem = function(index) {
  return this.data.items.splice(index, 1);
};

list = new List({
  data: {
    items: [
      {
        name: "Name1"
      }, {
        name: "Name2"
      }
    ]
  }
});

list.appendTo('.Page');

Renders to this:

<div class="ItemsList">
  <ul each="{{items}}"><li>
      Name1 <button on-click="function () {
    [native code]
}">Remove</button>
    </li><li>
      Name2 <button on-click="function () {
    [native code]
}">Remove</button>
    </li></ul>
</div>

And the button doesn't trigger the removeItem function which is part of the List prototype.

Any idea what I may be doing wrong?

What is "Reactive"?

From the README:

It aims to have a similar API to Reactive, but allow composition of views, like React

These are not hyperlinked. "React" I think refers to this library. It's not clear what "Reactive" refers to.

Ripple + jade

I come from a project who use jade as template engine. Is possible combine both jade template with a ripple template?

With jade, I can do:

jadeTemplate({item: item});

For the moment I do something like

var Template = ripple(jadeTemplate());

I need to call it, to get the template as string.

Can I do in other way?

CustomEvent is not newable in IE11

Hi,
ripples.js is very good! However an error has occurred in IE11.

the error in line 48

rippleEnd           = new CustomEvent("rippleEnd", {detail: $ripple}),

IE11's CustomEvent is not able to new.
I add some code and use in my project.
It is following code and exec in if browser's CustomEvent is not newable.

rippleEnd = document.createEvent("CustomEvent");
rippleEnd.initCustomEvent("rippleEnd", false, false, { detail: $ripple });

for your information.

I thank you for reading my funny english through.

Push latest to npm

I'd like to use this with our browserified app without component. The latest code on npm is v0.4.0. Can you push the latest please?

How to compose views one inside of the other?

After readed the examples https://github.com/ripplejs/ripple/wiki/Composing-Views
I like to know if is possible compose one view, inside of the other.

I have something like this:

 <div class="social-networks">
    <a href="http://twitter.com/">Twitter</a>
    <a href="http://facebook.com/">Facebook</a>  
</div>

and I would like to add inside of the oter views, in diferent points like:

 <div class="user-profile-networks">
    <p>{{name}}</p>
    <p>{{lastName}}</p>
    <p>{{email}}</p>
  <!-- social network view here-->
 <br> 
 <p>{{adress}}</p>  
</div>

Is this possible?

ripple vs. reactive

would love to see a little section in the readme or this issue about the differences / design decisions between these two reactive engines.

Example setup without using Component

It would be rather useful to see a working example without using component. I am considering using ripple in my current project- which uses requirejs to manage modules.
Else, if I get some guidance I could eventually do this myself and submit a PR.

Each iterator on the repeated DOM element instead of container

Following the iteration example, i've noticed that the directive is passed in the container element instead of the element being cloned at each loop.

This might present some limitations, one example being the following.
Let's say I have a ul that contains my data items. When there are no items to show I wan't to show an li with some specific formatting. If I try that now, just by having the extra liinside the element where each is applied it breaks.

This is more a question than a suggestion, just curious about the reasons behind that design option.

Reactive arrays

I have a property set to an array and I want to be able to get its length attribute on the template.
Is that possible using ripplejs/ripple standalone or using any plugin?

My code looks like the following:

var ripple = require('ripple');
var template = '<div>{{items.length}}</div>';
var View = ripple(template);

View.attr('items', {type: 'array'});

View.on('ready', function(view) {
  setTimeout(function () {
    view.get('items').push(1); // does not update the template
  }, 1000);
});

var view = new View({items: [10, 20, 30, 0, 4]});

view.appendTo(document.body);

Cannot get the sample composed view to work

Hi, im now following the docs to learn the essentials of Ripple but im stuck on the following code.

events      = require "events"
each        = require "each"
dispatch    = require "dispatch"
ripple      = require 'ripple'

Avatar = ripple 'Avatar: {{username}}'
Link = ripple 'Link: {{username}}'

Profile = ripple('#profileTemplate')
  .compose 'profile-avatar', Avatar
  .compose 'profile-link', Link

profile = new Profile
  data:
    username: 'lmartins'

profile.appendTo document.body

Im referencing a template that I have on my document, like this:

<script type="text/template" charset="utf-8" id="profileTemplate">
      <div class="Profile">
        <profile-avatar username="{{username}}"></profile-avatar>
        <profile-link username="{{username}}"></profile-link>
      </div>
    </script>

In runtime this outputs:

<div class="Profile">
        Avatar: lmartins
        <profile-link username="{{username}}"></profile-link>
      </div>

Any ideia why the second custom-element isn't being outputting anything?

Child views have the same lifecycle handlers

With the each plugin, the dynamic views that are created have the same lifecycle handlers as the parent view because we're just re-using that parent constructor.

eg. You create a View and add a created handler. Then you use the each plugin and for each view that is created for the items, that created handler will be fired.

It needs to be changed to something like:

function ChildView(){
  View.apply(this, arguments);
}
ChildView.prototype = Object.create(View.prototype);

But then it missed out on parse - but that should probably be on the prototype.

Or just create a new ripple view. This creates a cyclical dependency which is pretty hard for standalone builds.

Emit "mounted" event on child views

According to this documentation, a mounted event should be triggered, each time a view enters the DOM.

This implies, that each time a view is mounted, each of its child views (attached via .compose()) should emit a mounted event as well.

Currently this is not the case. I will look into this (I guess it should be fairly straightforward to implement this) and see if I can provide a pull-request, but for now I wanted to know your opinions of this, and if this would be indeed the correct, expected behavior.

Multiple views, singe data source?

Is there any way to use a central data source that multiple views make and watch for changes with?

I've toyed around with having models share observers but it fails when you have nested views (so when using the each plugin).

Also, brilliant work you've done with this framework! It's been very useful, so thank you.

consistent plugin api

I think we should follow a consistent plugin api like how rework, component/model, builder.js does:

var View = ripple(tmpl)
  .use(refs())

// instead of 
  .use(refs)

that way the plugin maker can add options later on without breaking backwards compatibility. It's also a pain to find out which ones uses the first method and which ones the second, especially when you use many plugins at once. What do you think?

how does data flow to children?

Starting to play with ripple and reading the composition docs. It says that the parents pass the data to the children. I'm a bit confused on what you give the parents to render the children correctly. Is it an array of objects? Example:

[
  {
    username: "anthony",
    ...
  },
  {
    username: "matt",
    ...
  }
]

Firing events/methods when data changes

Following Anthony's suggestion, im posting this question here since there isn't yet a StackOverflow or forum where this kind of request probably fit better.
Hope you don't mind and can point some directions to where look further.

Im trying to build a small component, based on the iteration example, where I have a list of numbers that I can add or remove items.

I've published the working sample here:
http://jsfiddle.net/lmartins/VPB93/

Let's say I wanted to achieve the following:

  • When no items on the list show a "no items" message instead - This would happen of first page load and if the user deleted all items

What would you suggest doing to achieve this, I though of custom events or setting an watcher on the items array using the observer plugin but im still lacking the knowledge to figure how all the parts fit together.

Trying to build the examples

The directions say "In each directory run make build, then open up index.html." When I cd into a directory and type make build, I get the error make: *** No rule to make target `build'. Stop.

Can anyone help me get this started?

Make build at the top level does work, and seems to install a shit-ton of things, so the tool is actually working...

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.