Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pedrozath/opalla
Opalla: A front-end framework written on Ruby on top of Opal.
https://github.com/pedrozath/opalla
Last synced: 2 months ago
JSON representation
Opalla: A front-end framework written on Ruby on top of Opal.
- Host: GitHub
- URL: https://github.com/pedrozath/opalla
- Owner: pedrozath
- License: mit
- Created: 2017-05-15T15:26:09.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-05-25T14:23:14.000Z (over 7 years ago)
- Last Synced: 2024-10-05T21:45:48.359Z (3 months ago)
- Language: JavaScript
- Homepage:
- Size: 77.1 KB
- Stars: 5
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Opalla
![Opalla](opalla.gif)Opalla brings Rails way to the front-end. It follows a Rails conventions mixed with a little of Backbone.
It's built on top of `opal` and `opal-rails`.
## Installation
Add this line to your application's Gemfile:```ruby
gem 'opal-rails'
gem 'opalla'
```Additionally, if you want to use `haml`, add:
```ruby
gem 'opal-haml'
```
(That's actually ultra-highly recommended)And then execute:
```
$ bundle
```Then run:
```sh
rails g opalla:install
```
Opalla is a front-end MVC framework. So you will to have this folder structure:
```
your_app
\_app
\_assets
\_javascripts
\_components
\_controllers
\_lib
\_collections
\_models
\_views
```And that’s it! You’re ready to drive Opalla.
## Usage
### Router & Controllers
It all starts with the Opalla router. It will catch the current URL and direct to the controller/action, exactly like Rails does.So for example, say you have the following route:
```ruby
get 'pages#index'
```You can generate controllers by running the default Rails controller generator:
```sh
rails g controller pages
```
If you just installed Opalla on your existing app and want to generate Opalla controllers for it, just re-run the command above and leave Rails do the rest! (It won't overwrite anything unless you explicitly ask for).
`Opalla::Router` will automatically import the routes and instantiate the `PagesController` inside your `javascripts/controller/pages_controller.rb` and trigger the `index` action:
```ruby
class PagesController < ApplicationController
def index
el.html 'Hello World!'
endend
```That would replace the `` tag with 'Hello World', as the default `el` for a controller. If you want to change that, you can add `el 'YOU_SELECTOR_HERE'`, in a jQuery selector fashion. So for example:
```ruby
class PagesController < ApplicationController
el '.main-content'def index
el.html 'Hello World!'
endend
```### Templates
Your Opalla templates will live under `app/assets/javascripts/views`. There you have `./controllers` and `./components`. Note that components templates should start their names with `_`, just like `partials`.Opalla will automatically have your templates folder added to your server side (Rails). So that means your templates will be rendered server-side and client-side. Yay!
The template will be able to get any access variables (`@variable`) and `methods`. Please note that you have to have both set on server and client sides.
Server-side:
```ruby
class PagesController < ApplicationController
helper_method :something_awesomedef index
@dude = 'Pedro'
enddef something_awesome
'Rails'
endend
```
Client-side, note that all methods are available by default, no need to set them as `helper_methods`:
```ruby
class PagesController < ApplicationController
el '.main-content'def index
@dude = 'Pedro'
render
enddef something_awesome
'Rails'
endend
```The following `haml` layout would work for both sides:
```haml
%main
The dude is called #{@dude}.
He works with #{something_awesome}```
If you want to share variables with your front-end Opalla MVC, that’s ok. Use the `expose` method automatically available on your server-side controllers:
```ruby
def index
expose message: 'Hello World!',
my_array: [1,2,3]
end```
And then you can use the data normally in your views:
```haml
%p= message
%p= my_array.join('/')
```That variables will be automatically available on both sides of your application.
### Components
`app/assets/javascripts/components` is where you components live. They will by default render the folder located on `app/assets/javascripts/views/components/_COMPONENT_NAME` (without the '_component' part of the name)To create components:
```sh
rails g opalla:component my_component
```
They are instantiated and rendered from the controller layout, like this:
```haml
%main
The dude is called #{@dude}.
He works with #{something_awesome}
component(:contact_box)```
That will look for the component `app/assets/javascripts/components/contact_box_component.rb`:
```ruby
class ContactBoxComponent < ApplicationComponent
end
```#### Model Data
The components can get their data from a `Opalla::Model`. Here's how it goes:First, generate your model:
```sh
bin/rails g opalla:model contact_info
```Let’s add a simple attr_accessor:
```ruby
class Opalla::Model
attr_accessor :email
end
```In the server-side controller you can expose the data, so that will be rendered from the server as default (no one wants blank pages to maybe hurt the SEO):
```ruby
class PagesController < ApplicationController
@contact_info = ContactInfo.new
@contact_info.email = '[email protected]'
expose contact: @contact_info
end
```Then, in your server side, you don’t need anything for this case, except for render:
```ruby
class PagesController < ApplicationController
el '.main-content'def index
render
endend
```
In the controller template:
```haml
%main
component(model: @contact_box)```
In the component template:
```haml
.contact-info
.email= model.email```
In the model (`app/assets/javascripts/models/contact_info.rb`):
```ruby
class ContactInfo
def initialize
end
end
```### Collection Data
Generate collections:
```sh
bin/rails g opalla:collection products
```Opalla will automatically assume that the model is the singular name. So `products` for example is a collection of `product` model. So you have to have the `product` model as well.
When working with collection components, you’ll often want to work with `data-attributes`. Opalla has a nifty way to help you:
Consider you have the following component:
```ruby
class ProductComponent < ApplicationComponentend
```With the following collection (notice the binding):
```ruby
class Products < Opalla::Collection
bind :price, :category
end
```On your collection model, you set data:
```ruby
class Product < Opalla::Model
data :price, :category, :model_id
end
```On your component template:
```haml
.products
collection.each |product|
.product{data=product.data}
end
end
```That will generate data attributes: `data-price`, `data-category`, `data-model-id`, the last enabling you to incorporate events in a very simple fashion
```ruby
class ProductComponent < ApplicationComponent
events 'click .product' -> target { buy(collection.find(target)) }
end
```That would trigger the buy element providing the `model` as argument. That’s because the `find method` in collections will look for the element or closest ancestor that has a `data-model-id` and return the model itself for you. Really easy!
Check the next chapter to see more ways on how collections can be very useful.
### Bindings
You can bind data from a model or collection to the component. That will trigger a `#render` action on the component:
```ruby
class ContactBoxComponent < ApplicationComponent
bind :email, :nameend
```
And that's it! Everytime the resource attributes change, being it a `model` or a `collection`, the component will be re-rendered.
#### 2-way binding
If you assign a `[data-bind='ATTRIBUTE_NAME']` to an input element on your template, it will change look for the closest ancestor that has `[data-model-id]` and change its attribute whenever you change the input.Example:
```haml
.product{data: product.data} # it is expected you set the model data
input{data-bind: 'name'}
```### Events
Similarly to Backbone, you can add events in the following way:```ruby
class PagesController < ApplicationController
el '.main-content'
events 'click a' => :do_somethingdef index
el.html 'Hello World!'
enddef do_something
alert 'I\'m doing something!'
endend
```
You can also provide a `lambda` instead:
```ruby
class PagesController < ApplicationController
el '.main-content'
events 'click a' => { alert "I'm doing something!" }def index
el.html 'Hello World!'
endend
```
You can also access the targetted object like this:```ruby
class PagesController < ApplicationController
el '.main-content'
events 'click a' => target { alert 'I\'m doing something!' }def index
el.html 'Hello World!'
enddef do_something
end
end
```
Please note that all events have their default behavior prevented by default.
## Development
The project is on beta phase. It's missing:* Specs
* Tests
* Rubocops
* ActiveRecord models supportFork and make a PR. Or talk to me at `[email protected]`.
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).