Where do I initialize backgrid in my Backbone/Rails app? - ruby-on-rails

I have a Backbone.js app and am trying to integrate with Backgrid, but I am having trouble understanding where I should be calling new Backgrid. I tried calling it in my view after things get rendered but appending the grid doesn't work because things aren't actually rendered yet. Here is some code:
SpreadsheetIndex.js.coffee
D3.Views.SpreadsheetsIndex = Support.CompositeView.extend
initialize: (options) ->
this.tables = options.tables
this.resources = options.resources
_.bindAll(this, 'render')
render: ->
this.renderTemplate()
this.renderSpreadsheets()
resources = this.resources
this.tables.each (table) ->
subset = resources.subcollection
filter: (resource) ->
resource.escape('table_id') == table.escape('id')
grid = new Backgrid.Grid
columns: table.attributes.columns
collection: subset
$("#"+table.escape('id')).append(grid.render().$el);
return this
renderTemplate: ->
this.$el.html(JST['spreadsheets/index']({ spreadsheets: this.tables }))
renderSpreadsheets: ->
self = this
self.$('tbody').empty();
spreadsheets/index.jst.ejs
<% spreadsheets.each(function(spreadsheet) { %>
<h4><%= spreadsheet.escape('name')%></h4>
<div id='<%= spreadsheet.escape('id') %>'></div>
<% }) %>
The issue is that the $("#"+table.escape('id')) selector does not select anything because the template hasn't rendered yet. It feels like I'm putting this in the wrong place. What am I doing wrong?

I'd guess that you want to use the view's #$ method to instead of $ to localize the selector to the view's el:
this.tables.each (table) =>
#...
#$("#"+table.escape('id')).append(grid.render().$el);
Note that -> has become => (to get the right #/this) and it now uses #$ instead of $.
While I'm here, you can do a couple other things to make your code more ideomatic:
Say class D3.Views.SpreadsheetsIndex extends Support.CompositeView instead of the JavaScripty D3.Views.SpreadsheetsIndex = Support.CompositeView.extend.
Use # instead of this, for example #tables = options.table rather than this.tables = options.table.
You can use string interpolation instead of + if you think it is cleaner:
#$("##{table.escape('id')}")
You rarely need bindAll, instead of _.bindAll(this, 'render') you could define render as render: => to get the binding to happen automatically.
You rarely need the var self = this trick in CoffeeScript, you can usually use a => instead. And you don't need either one here:
renderSpreadsheets: ->
self = this
self.$('tbody').empty();
you can just renderSpreadsheets: -> #$('tbody').empty()

Related

Convert a method call or assignment to a function in F#

I would like to use some object-oriented code in a more functional way.
My current approach has been the following:
let addControl (child: Control) (parent: Control) =
parent.Controls.Add child
parent
let setDock dock (control : Control) =
control.Dock <- dock
control
form |> addControl button
button |> setDock DockStyle.Fill
Is there a simpler way I can define these functions?
If I take the JS approach I could define something like the following:
const fixMethod = name => value => parent => (parent[name](value), parent)
const resumeLayout = fixMethod("ResumeLayout")
resumeLayout(true)(form)
const fixAssign = name => value => parent => ({...parent, [name]: value})
const setDock = fixAssign("Dock")
setDock(DockStyle.Fill)(button)
There are various tricks you could do in F#, but none of those will make your code much nicer - I would say that most tricks you can do will actually only make it more complex and unidiomatic.
There is nothing wrong with writing some imperative-looking code if that's what the underlying libraries look like. F# does have a few features that make this easier - you can, for example, specify mutable properties directly when calling a constructor, so you can set Dock as follows:
let button = new Button(Dock = DockStyle.Fill)
let form = new Form()
form.Controls.Add(button)

Building a map for parallel step from directory names [duplicate]

For example, the groovy File class has a nice iterator that will filter out just directories and not files:
void eachDir(Closure closure)
When I use eachDir, I have to use the verbose method of creating the collection first and appending to it:
def collection = []
dir1.eachDir { dir ->
collection << dir
}
Any way to get it back to the nice compact collect syntax?
I don't know of any "idiomatic" way of doing this, nice riddle! =D
You can try passing the eachDir, or any similar function, to a function that will collect its iterations:
def collectIterations(fn) {
def col = []
fn {
col << it
}
col
}
And now you can use it as:
def dir = new File('/path/to/some/dir')
def subDirs = collectIterations(dir.&eachDir)
def file = new File('/path/to/some/file')
def lines = collectIterations(file.&eachLine)
(that last example is equivalent to file.readLines())
And only for bonus points, you may define this function as a method in the Closure class:
Closure.metaClass.collectIterations = {->
def col = []
delegate.call {
col << it
}
col
}
def dir = new File('/path/to/some/dir')
def subDirs = dir.&eachDir.collectIterations()
def file = new File('/path/to/some/file')
def lines = file.&eachLine.collectIterations()
Update: On the other hand, you might also do:
def col = []
someDir.eachDir col.&add
Which I think is quite less convoluted, but it's not leveraging the collect method as you requested :)
Not for the specific example that you're talking about. File.eachDir is sort of a weird implementation IMO. It would have been nice if they implemented iterator() on File so that you could use the normal iterator methods on them rather than the custom built ones that just execute a closure.
The easiest way to get a clean one liner that does what you're looking for is to use listFiles instead combined with findAll:
dir1.listFiles().findAll { it.directory }
If you look at the implementation of eachDir, you'll see that it's doing this (and a whole lot more that you don't care about for this instance) under the covers.
For many similar situations, inject is the method that you'd be looking for to have a starting value that you change as you iterate through a collection:
def sum = [1, 2, 3, 4, 5].inject(0) { total, elem -> total + elem }
assert 15 == sum

AngularJS: how do I pass an :id parameter from Rails?

I need to get data from my Ruby on Rails application, for that I made a pretty simple AngularJS controller:
# /app/assets/javascripts/angular/comments.js.coffee
app.controller 'CommentsController', ['$http', ($http) ->
store = this
store.comments = []
$http.get('/photos/3287.json').success (data) ->
store.comments = data
return
]
It works absolutely fine with the hard-coded :id, but I'm stuck with how to make it change dynamically. What is the easiest way to get an :id from Rails?
I suppose, you wanna edit it? So, you shouldn't use AJAX, you should create factory and use Angular $resource, so you fetch it with :id, set it to $scope, and use it in future.
MORE ABOUT Angular $resource - use Angular way
I believe you can include :id in the URL and then pass the id as a parameter to the get.
# /app/assets/javascripts/angular/comments.js.coffee
app.controller 'CommentsController', ['$http', ($http) ->
store = this
store.comments = []
$http.get('/photos/:id.json', {id: photo.id}).success (data) ->
store.comments = data
return
]
EDIT: I may have misunderstood. This is how you pass an id to $http, but if you need to get the id itself use $resource as Oleg had answered.
Thanks everybody. Here is my working code.
# comments.js.coffee
app = angular.module('comments', ['ngResource'])
app.controller 'CommentsController', ['$scope', 'GetComments', ($scope, GetComments) ->
store = this
store.response = []
$scope.init = (photo_id) ->
GetComments.get({id: photo_id}).$promise.then (data) ->
store.response = data.toJSON().comments
return
return
]
app.factory 'GetComments', ['$resource', ($resource) ->
$resource('/photos/:id.json', null)
]
Also I had to add ng-init to my view like this:
# foo.html.haml
%div{'ng-controller' => 'CommentsController', 'ng-init' => "init(#{#photo.id})"}

ReactJS with dynamic type objects

I am working on a project to convert some of the rails view layer to ReactJS. One of the challenge that I have is to render a list of dynamic type of objects (Objects are using STI).
for example, I am trying to render a bag of fruits, and each fruit has a specific partial views in rails. In rails, I would do
fruits.each do |fruit|
#fruit.type could be orange, apple, banana, etc.
render 'fruits/' + fruit.type
end
How do i do this in ReactJS? Is it possible?
You can just create an object.
var things = {
foo: FooComponent, ...
};
And then get a component from that.
var key = 'foo';
var Component = things[key];
return <Component />
Note that the variable must start with an uppercase letter if you're using jsx, otherwise it will assume you mean the html element <component></component>.
Or don't use jsx here.
React.creatElement(things[key], null);
Without additional information on where you need to do this, I'm going to assume you need it at render time, in which case: just do the same thing in JavaScript.
.....React.createClass({
...
getInitialState: function() {
return {
fruits: this.props.fruits || []
};
},
...
render: function() {
var fruits = this.state.fruits.map(function(f) {
return <li>{f.type}</li>;
});
return <ul>{fruits}</ul>;
},
...
});

watch expression is not picking up on model change from ng-change

I have the following
Rails HAML:
= select_tag "some-class",
options_for_select([['None', '']], ''),
{ class: 'some-other-class',
'ng-model' => 'someModel',
'ng-options' => 'option.name for option in someList',
'ng-change' => 'updateSelected()'}
Angular Controller:
scope.updateSelected = ->
#logic for updating model lives here. Model updates successfully by using some values defined within scope. Includes the following:
scope.someModel = "some_new_value"
Angular Directive:
SomeClassDirective= ->
restrict: 'C'
link: (scope, element, attrs) ->
monitorFormFields = (newValue, oldValue) ->
console.log "this is the inner function call"
#logic for setting the inner _destroy field lives here
scope.$watch 'someModel', monitorFormFields
However, when the Select List value is changed, 'this is the inner function call' never prints.(it does print when the directive first initializes, ie at page load). My question therefore is: Why isn't the $watch expression triggering, and how do I get it to trigger?
Thanks!
With this HTML:
<select class="some-class" ng-model="someModel"
ng-options="option.name for option in someList"></select>
Here is a directive that will watch for a change to someModel:
myApp.directive('someClass', function () {
return {
restrict: 'C',
link: function (scope, element, attrs) {
var monitorFormFields = function (newValue, oldValue) {
console.log("this is in the inner function call");
}
scope.$watch('someModel', monitorFormFields);
}
}
});
Controller:
$scope.someList = [{ name: 'name1' }, { name: 'name2' }];
Note that you don't need to call a controller method to update someModel -- Angular does that automatically for us because of the ng-model attribute. So, the directive only needs to $watch for a change to that $scope property.
Fiddle.
I would like to from the element fetch a sibling with [_destroy] in the name and set it to either "0" or "1" depending on the value of the select box.
A more Angular approach would be to have model properties control whether "0" or "1" is displayed. E.g., in your controller:
$scope.destroy1 = "0";
$scope.destroy2 = "0";
In your HTML:
<div>{{destroy1}}</div>
<div>{{destroy2}}</div>
In monitorFormFields() you can change the values of these scope properties, and the view will automatically update -- there is no need to "find" siblings or update .val()ues.

Resources