ReactJS with dynamic type objects - ruby-on-rails

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>;
},
...
});

Related

How to embed html in Google Forms question's description

I am trying to adapt Zack Akil's script to generate a Google Form from a Google Sheet using App Script, but one thing that I am struggling with is to make the sheet's input parsed as HTML. I generate a form based on my sheet, all the text on cells is placed in Forms as plain text, the HTML is not parsed (see figure below).
I pasted the script from Zack and I kindly ask you to point out where should I modify in order to have this parsed on the form.
function getSpreadsheetData(sheetName) {
// Return an list of objects (one for each row) containing the sheets data.
var arrayOfArrays = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName || 'Sheet1').getDataRange().getValues();
var headers = arrayOfArrays.shift();
return arrayOfArrays.map(function (row) {
return row.reduce(function (memo, value, index) {
if (value) {
memo[headers[index]] = value;
}
return memo;
}, {});
});
}
function create_ranges_for_data(form, data, data_section_name){
// loop throughh each row
data.forEach(function (row) {
// create a new question page
form.addPageBreakItem()
// add page title
form.addSectionHeaderItem()
.setTitle(data_section_name);
// create number range input with the title being the document to be labeled
form.addScaleItem()
.setTitle(row[data_section_name])
.setBounds(1, 10)
.setRequired(true);
});
}
function make_form_using_column(column_name) {
// create a new Google Form document
var form = FormApp.create('Data labelling - ' + column_name)
desc = "Thank you for taking the time to label this data!";
form.setDescription(desc);
form.setProgressBar(true);
form.setShowLinkToRespondAgain(false)
var data = getSpreadsheetData();
create_ranges_for_data(form, data, column_name);
}
function gen_form(){
var COLUMN_TO_USE = 'Input text'
make_form_using_column(COLUMN_TO_USE);
}
You can't use HTML text formatting. most sites block it because it poses a security risk. You might need to install an add-on or, like fullfine said, use bold text.

Dynamic Filters for OData Read Based on Input

I have the requirement to send filter values via OData-service, to fill a table with relevant entries.
So basically there are input fields, where you can select e.g. "AA" (american airlines) for Carrier-ID.
So the filter values need to be created dynamically, regarding to the user input.
I tried following:
var aFilters = [
new sap.ui.model.Filter({
path: "Carrid",
operator: sap.ui.model.FilterOperator.EQ,
value1: "{selection>/Carrid}"
})
];
oModel.read("/SFLIGHTSSet",{
method: "GET",
filters: aFilters,
success: function(oData2, oResponse) {
var oJSONModel = new sap.ui.model.json.JSONModel();
oJSONModel.setData({
modelData: oData2.results
});
oTable.setModel(oJSONModel);
oTable.bindRows("/modelData");
},
error: function(oError) {
console.log("Error!");
}
});
But that doesn't work.
I receive in back-end following request:
"( Carrid eq '{selection>/Carrid}' )"
So the binding doesn't work in the filter-creation...
The binding is correct because I can use it the same way in a Label:
new sap.m.Label({
text: "{selection>/Carrid}"
});
I researched a lot and know that people have problems with it in XML views.. but couldn't find any solution for JS-Views.
I guess your problem is in the line
"{selection>/Carrid}"
Get the value of the User-Input from the Control somehow like this
var sCarrid= this.byId("MySelection").getBindingContext("selection").getProperty("Carrid");
and modify your Filter
var oFilters = [ new sap.ui.model.Filter("Carrid",
sap.ui.model.FilterOperator.EQ,
sCarrid) ];

How to index sub-content in Sitecore with Lucene?

I'm using Sitecore 7.2 with MVC and a component approach to page building. This means that pages are largely empty and the content comes from the various renderings placed on the page. However, I would like the search results to return the main pages, not the individual content pieces.
Here is the basic code I have so far:
public IEnumerable<Item> GetItemsByKeywords(string[] keywords)
{
var index = ContentSearchManager.GetIndex("sitecore_master_index");
var allowedTemplates = new List<ID>();
IEnumerable<Item> items;
// Only Page templates should be returned
allowedTemplates.Add(new Sitecore.Data.ID("{842FAE42-802A-41F5-96DA-82FD038A9EB0}"));
using (var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))
{
var keywordsPredicate = PredicateBuilder.True<SearchResultItem>();
var templatePredicate = PredicateBuilder.True<SearchResultItem>();
SearchResults<SearchResultItem> results;
// Only return results from allowed templates
templatePredicate = allowedTemplates.Aggregate(templatePredicate, (current, t) => current.Or(p => p.TemplateId == t));
// Add keywords to predicate
foreach (string keyword in keywords)
{
keywordsPredicate = keywordsPredicate.And(p => p.Content.Contains(keyword));
}
results = context.GetQueryable<SearchResultItem>().Where(keywordsPredicate).Filter(templatePredicate).GetResults();
items = results.Hits.Select(hit => hit.Document.GetItem());
}
return items;
}
You could create a computed field in the index which looks at the renderings on the page and resolves each rendering's data source item. Once you have each of those items you can index their fields and concatenate all of this data together.
One option is to do this with the native "content" computed field which is natively what full text search uses.
An alternative solution is to make an HttpRequest back to your published site and essentially scrape the HTML. This ensures that all renderings are included in the index.
You probably will not want to index common parts, like the Menu and Footer, so make use of HTMLAgilityPack or FizzlerEx to only return the contents of a particular parent container. You could get more clever to remove inner containers is you needed to. Just remember to strip out the html tags as well :)
using HtmlAgilityPack;
using Fizzler.Systems.HtmlAgilityPack;
//get the page
var web = new HtmlWeb();
var document = web.Load("http://localsite/url-to-page");
var page = document.DocumentNode;
var content = page.QuerySelector("div.main-content");

Backbone.js: Change datetime field from Rails

When I print the created_at field of a model using Backbone.js( <i> {{created_at}} </i>
), I'm getting: 2011-08-07T12:03:00Z.
I'm trying to change the date to a readable format for hours and I'm not being able to.
I want the T and Z to be removed before printing.
thanks
Change the variable in your template context, or add a new one. I would add a new one.
If this is in your render function, it may be changed to something like this:
render: function() {
var context = this.model.toJSON();
context['created_at_formatted'] = this.formatDate(context['created_at']);
var html = this.template.to_html(context);
$(this.el).html(html);
}
With a function added to the view like this:
formatDate: function(d) {
var pad = function (n) {
return n < 10 ? '0' + n : n;
};
// in case the date is a string; you can remove this if you know it will be a date
if (typeof date === 'string') {
d = new Date(d);
}
return [
d.getUTCFullYear(), '-',
pad(d.getUTCMonth() + 1), '-',
pad(d.getUTCDate()), ' ',
pad(d.getUTCHours()), ':',
pad(d.getUTCMinutes()), ':',
pad(d.getUTCSeconds())
].join("");
}
Then the template would be like this:
<i> {{created_at_formatted}} </i>
To simplify the date formatting function, you could also use a date formatting library like DateJS. You could also move the date formatting to the model.
Readable? Why not jQuery timeago?
jQuery timeago
In your Backbone model,
toTemplateData: ->
_.extend
created_duration: do => $.timeago #get("created_at") if #get("created_at")
In your Backbone view,
render: ->
#$el.html(#template(#model.toTemplateData() ))
In your template,
<time title="{{created_duration}}"></time>
You can use the strftime on your created_at
<i> {{created_at.strftime('%Y/%m/%d')}} </i>
Ben's answer is correct but the formatting of the date should really be in a model somewhere as it is business logic.
My variation of that would be:
render: function() {
var context = this.model.format().toJSON();
var html = this.template.to_html(context);
$(this.el).html(html);
}
And in your model, something like:
format() {
this.set('created_at_formatted', formatDate(this.get('created_at')));
return this;
}
formatDate: function(d) {
// format date stuff (See Ben`s answer)
return d;
}
And your template would render:
<i> {{created_at}} </i>
This removes some redundancy, promotes reuse and it is easier to read. Perhaps my answer needs a little work but hopefully you get the general idea.

Backbone.js why a model from a collection doesn't have url set?

I am still relatively new to Backbone. I'm just beginning to get a sense of how it works. I 've been using Rails for a while and it's what is giving me some hint at times of using Backbone. so here goes:
Simple, I have a Company model over in Rails say I do in javascript console
companies = new Backbone.Collection();
companies.url = '/companies';
companies.url; // '/companies'
companies.fetch();
company = companies.at(0);
company.url
The last line, "company.url" doens't return what I expect, what I expect is something like '/companies/12345' so that when I update company and decide to save it, it will know where to "put" to.
So does that mean that everytime I want something saved, I have to save on the whole collection?(!)
I would take a look at what company.url() is returning. Saving the whole collection should not be necessary.
I was trying your problem, and found that the models are not getting an id to it. So the url method on the models is not working. So i think you need to put your collections like below (what i tried)
cltn = Backbone.Collection.extend({
model:modelName,
parse:function(res){
var i = 0;
var itms = _.map(res.items, function(o){
o.id = ++i;
return o
})
return itms;
}
});
cltnInst = new cltn();
cltnInst.url="/combodata.json?";
cltnInst.fetch();
Then in your firebug type the below codes.
cltnInst.url; // this is a string props. output will be "/combodata.json?"
cltnInst.at(0).url() // this is a method props output will be "/combodata.json?/1"
combodata.json will be of this format
{
"identifier": "title",
"items": [
{
"title": "A",
"tag": "htmlcss",
"date": "today"
}, ...
]}
Please correct me if my answer is wrong.
I have actually made a mistake in the step where I make an attempt to create a new companies collection.
So instead of
var Companies = new Backbone.Collection()
I should really do something like this:
var Companies = Backbone.Collection.extend({
model: Company,
url : '/companies'
});
var Company = Backbone.Model.extend();
var companies_collection = new Companies()
companies_collection.fetch()
companies_collection.models[0].url() // '/projects/123'

Resources