gem react-rails, what is wrong with my coffee style? - coffeescript

It's my first time when I try to work with react. And I do not understand what's going on.. :)
A have:
Dislike = React.createClass
render: ->
if #props.auth == true
React.DOM.a
className: ''
React.DOM.i
className: 'fa fa-thumbs-o-down'
"Dislike (#{#props.num_dislike})"
else
React.DOM.i
className: 'fa fa-thumbs-o-down'
"Dislike (#{#props.num_dislike})"
Like = React.createClass
render: ->
if #props.auth == true
React.DOM.a
className: ''
React.DOM.i className: 'fa fa-thumbs-o-up',
"Like (#{#props.num_like})"
else
React.DOM.i
className: 'fa fa-thumbs-o-up'
"Like (#{#props.num_like})"
#LikeBox = React.createClass
render: ->
return (
React.createElement(Dislike, #props)
React.createElement(Like, #props)
)
In my view a have:
= react_component('LikeBox', {auth: current_user.present?,
num_like: 23,
num_dislike: 32,
link_like: like_suggestion_path(suggestion),
link_dislike: dislike_suggestion_path(suggestion)})
And when I open page a have:
<div data-react-class="LikeBox" data-react-props="{....}">
<a class="" data-reactid=".0">
<i class="fa fa-thumbs-o-up" data-reactid=".0.0">Like (23)</i>
</a>
</div>
But my expectations is:
<div data-react-class="LikeBox" data-react-props="{....}">
<a class="" data-reactid=".0">
<i class="fa fa-thumbs-o-up" data-reactid=".0.0">Like (23)</i>
</a>
<a class="" data-reactid=".0">
<i class="fa fa-thumbs-o-down" data-reactid=".0.0">Dislike (73)</i>
</a>
</div>
What is wrong with this block ?
#LikeBox = React.createClass
render: ->
return (
React.createElement(Dislike, #props)
React.createElement(Like, #props)
)

We can simply return an array of children elements of LikeBox
#LikeBox = React.createClass
render: ->
React.DOM.div
className: 'like-box'
[
React.createElement(Dislike, #props)
React.createElement(Like, #props)
]

Only 'Like' element will be rendered in LikeBox.
To make it work, you can do like this:
#LikeBox = React.createClass
render: ->
React.DOM.div
className: 'like-box'
React.createElement(Dislike, #props)
React.createElement(Like, #props)
In the above code, a div will be rendered which contains 2 children elements

Related

Resetting validation in vue

here's the example of my simple form which throws an error when the text field is empty. On the first submit everything is ok, but after next you see the error before submitting second message. Here's code:
<div id="app">
<v-app >
<v-dialog v-model="dialog">
<template v-slot:activator="{ on }">
<v-btn v-on="on">Open</v-btn>
</template>
<v-card>
<v-text-field
v-model="note"
:rules="noteRules"
></v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn #click="submit()">save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-app>
</div>
and app.js
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
dialog: false,
note: '',
noteRules: [
v => !!v || 'error'
],
}),
methods: {
clear() {
this.dialog = false;
//something here?
}
}
})
how should I reset the validation? here's codepen https://codepen.io/tutu-kaen/pen/oNjPPKe
Wrap your content of the card in a v-form, add a v-model and a ref to that v-form.
You can then access that v-form in your clear() by using this.$refs..
The formValid will be a boolean so you can easily check if a form is valid by using if (this.formValid) anywhere in your code, for example to disable the send button.
Example:
<div id="app">
<v-app>
<v-dialog v-model="dialog">
<template v-slot:activator="{ on }">
<v-btn v-on="on">Open</v-btn>
</template>
<v-card>
<v-form v-model="formValid" ref="myForm">
<v-text-field v-model="note" :rules="noteRules"></v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn #click="submit()">save</v-btn>
</v-card-actions>
</v-form>
</v-card>
</v-dialog>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
dialog: false,
note: '',
formValid: false,
noteRules: [
v => !!v || 'error'
],
}),
methods: {
submit() {
this.note = '';
this.dialog = false;
this.$refs.myForm.reset();
}
}
})
Codepen example

Nesting {{#each}} in Handlebars 304 error

My Nested {{#each}} does not work.
I am Scraping article titles to my page and I'm using MongoDB/Mongoose. For each article (that I named News) I want user to post comments and view previous comments.
My routes, console.log, and the database itself shows that my api routes are working, but I can't get the comments to display.
My handlebars has the articles rendering to screen, but when GETting the comments it returns a 304.
The Articles display as I intend, it only has a problem with the comments
{{#each News}} is each article
{{#each comment}} is nested inside each News.
{{#each News}}
<div class="panel-block is-active">
<ul>
<li>
<div class="level-left">
<h2 class="subtitle">
<a href="https://www.atptour.com{{this.url}}">
{{this.headline}}
</a>
</h2>
</div>
</li>
<li>
<img width="348" src="https://www.atptour.com{{this.thumbNail}}">
</li>
<li>
<p>{{category}}</p>
</li>
<li>
{{!-- on click remove class .is-hidden on #getComments --}}
<p id="showComments" data-id="{{this._id}}" >Comments</p>
</li>
<li>
{{#each comment}}
<article id="getComments" class="media is-hidden">
<div class="media-content">
<div class="content">
<p>
<small>{{this.time}}</small>
<br />
{{this.body}}
</p>
</div>
</div>
<div class="media-right">
<button class="delete"></button>
</div>
</article>
{{/each}}
{{!-- on click remove class .is-hidden on #postComments --}}
<a id="addComment" >Add Comment</a>
{{!-- TO POST A COMMENT --}}
<article id="postComment" class="media is-hidden">
<div class="media-content">
<div class="field">
<p class="control">
<textarea
class="textarea"
placeholder="Add a comment..."
></textarea>
</p>
</div>
<div class="level">
<div class="level-left">
<div class="level-item">
<a class="button is-info">Submit</a>
</div>
</div>
</div>
</div>
</article>
</li>
</ul>
</div>
{{/each}}
In the {{#each comment}} {{this.time}} and {{this.body}} is blank. But if I simply put {{this}} I get the _id if each comment. The context must be wrong but I don't know why. The comments are properly associated to the News because I can check the get route and it's all there correctly.
Here are the schemas if it helps
new articles
const NewsSchema = new Schema({
headline: {
type: String,
required: true,
},
thumbNail: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
url: {
type: String,
required: true,
},
// Comments will populate the News
comment: [
{
type: Schema.Types.ObjectId,
ref: "Comment",
},
],
});
const News = mongoose.model("News", NewsSchema);
comments
const CommentSchema = new Schema({
time: {
type: Date,
default: Date.now,
required: true,
},
body: {
type: String,
required: true,
},
});
const Comment = mongoose.model("Comment", CommentSchema);
It wasn't a handlebars problem at all!
It was a route problem.
I was doing this:
app.get("/", function(req, res) {
db.News.find()
.then(News => {
res.render("index", { News });
})
.catch(err => {
console.log(err);
});
});
When I should have been doing this
app.get("/", function(req, res) {
db.News.find()
.populate("comment")
.then(News => {
res.render("index", { News });
})
.catch(err => {
console.log(err);
});
});
I forgot to populate in the res.render. (I was populating the api route, but not this 1!)

Semantic UI Custom Rule Validation for Select Drop-Down Field

I am trying to add some custom logic to my semantic ui validation but can't figure out what I am doing wrong.
Basically, when the user selects "Yes" from the drop-down, I would like to make the "input_field" mandatory. If the user selects "No", the "input_field" becomes optional and the form can be submitted.
I tried searching for examples and followed some code from the Semantic Ui website but can't figure out what I am missing. Any advice would be appreciated as I am on a deadline for a project I am working on.
Form:
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
Validation:
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
},
input_field: {
identifier: 'input_field',
depends: 'select',
rules: [
{
type: 'empty',
prompt: function() {
$('.select').on('change', function() {
if( this.value == 'Yes') {
return "Custom Validation";
}
return false;
}).trigger("change");
}
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
});
</script>
Figured out a solution for this! It might not be the best answer but it works and does what I am looking for.
<div class="ui dimmer">
<div class="ui huge text loader">Loading</div>
</div>
<form method="post" action="" class="ui form" autocomplete="on">
<div class="ui segment">
<div class="ui two fields">
<div class='field'>
<div class="ui selection dropdown">
<input type="hidden" class="selectOption" name="select">
<i class="dropdown icon"></i>
<div class="default text">Select an option</div>
<div class="menu">
<div class="item" data-value="Yes">Yes</div>
<div class="item" data-value="No">No</div>
</div>
</div>
</div>
<div class="field">
<input id="input_field" name="input_field" type="text"/>
</div>
</div>
</div>
<button id="submit" class="ui green button" name="submit" type="submit">Submit</button>
</form>
<script>
$('.ui.form').form({
keyboardShortcuts: false,
on: 'blur',
inline: 'true',
fields: {
selectOption: {
identifier: 'select',
rules: [
{
type: 'empty',
prompt: 'Please select an option'
}]
}
},
onSuccess: function() {
$('.ui.dimmer').dimmer('show');
},
onFailure: function() {
event.preventDefault();
}
}
);
$('.selectOption').on('change', function() {
if ( this.value == 'Yes' ) {
$('.ui.form').form('add rule', 'input_field', ['empty', 'integer']);
$('.ui.form').form('add prompt', 'input_field', 'Enter an integer');
}
if ( this.value == 'No' ) {
$('.ui.form').form('remove prompt', 'input_field');
$('.ui.form').form('remove rule', 'input_field');
}
}).trigger("change");
});
</script>
I was able to implement the validation rule by extending Semantic UI setting rules.
See below example:
$.fn.form.settings.rules.dependsOnFieldValue = function (value, dependFieldValue) {
var identifier = dependFieldValue.split('[')[0];
var dependValue = dependFieldValue.match(/\[(.*)\]/i)[1];
if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
matchingValue = $('[data-validate="'+ identifier +'"]').val();
}
else if($('#' + identifier).length > 0) {
matchingValue = $('#' + identifier).val();
}
else if($('[name="' + identifier +'"]').length > 0) {
matchingValue = $('[name="' + identifier + '"]').val();
}
else if( $('[name="' + identifier +'[]"]').length > 0 ) {
matchingValue = $('[name="' + identifier +'[]"]');
}
return (matchingValue !== undefined)
? !( dependValue.toString() === matchingValue.toString() && value === '')
: false
;
};
Then in the form validation initializer you will pass the desired values as below:
$(".ui.form").form({
fields: {
select: {
identifier: 'select',
rules : [
{
type : 'empty'
}
]
},
input_field: {
identifier : 'input_field',
rules : [
{
type : 'dependsOnFieldValue[select[Yes]]',
}
]
},
...
}
});
Notice that we pass the <select> identifier (in this case also called select) within the first [] and then the value that we want to see to make the input_field mandatory ("Yes" in this case).

Scala.js webloaded js libraries not present?

I setup a project using scala.js.
At the web part (playframework) I added a static library bxslider.
With scala.js I add a complete new slider (div, ul and li). Without scala.js all works fine, with scala.js the inserted code is not going to be a slider.
I tried to pass a script part with bxSlider() to the correct id. No effect. I get the error bxSlider() is no function.
It seemed to me, that their is no access to bxSlider. Where is the error?
object WidgetSingleArticleSlider {
def articleEntry(x: SharedArticle, addToCartText: String) = {
li(
`class`:="wgsp-item",
a(
href:="#",
figure(
img(src:=x.articleDescription.pictureSeq.headOption.getOrElse(Pictures.emptyPath))
)
),
p(
`class`:="wgsp-title",
a(
href:="#",
x.articleDescription.title
)
),
p(
`class`:="wgsp-price",
(if(x.price.articlePrice(1).specialSubTotal.isDefined)
x.price.articlePrice(1).specialSubTotal.get.formatted("%,.2f ")
else x.price.articlePrice(1).subTotal.formatted("%,.2f ")) + x.price.articlePrice(1).currency
),
div(
`class`:="row no-gutter",
div(
`class`:="col-xs-12 text-center",
a(
`class`:="btn btn-third-col",
href:="#",
addToCartText
),
div(`class`:="gap-30")
)
)
)
}
def toHtml(title: String, articleSeq: Seq[SharedArticle], addToCartText: String) = {
div(
`class`:="widget wg-specials store-alt box-with-pager mobile-collapse",
h3(
`class`:="wg-title mobile-collapse-header store-alt",
title
),
div(
`class`:="wg-body mobile-collapse-body",
ul(
id := "tium",
`class`:="vertical-bx-1",
articleSeq.map(e => articleEntry(e,addToCartText))
)
)
)
}
}
In main.scala.html this is added at the end:
<script src="#routes.Assets.versioned("js/jquery-1.11.0.min.js")"></script>
<script src="#routes.Assets.versioned("js/jquery-ui-1.10.4.custom.min.js")"></script>
#*<script src="#routes.Assets.versioned("plugins/jquery.bxslider.min.js")"></script>*#
<script src="#routes.WebJarAssets.at(webJarAssets.locate("js/jquery.bxslider.js"))"></script>
<script src="#routes.Assets.versioned("js/bootstrap.min.js")"></script>
<script src="#routes.Assets.versioned("js/jquery-accessibleMegaMenu.js")"></script>
<script src="#routes.Assets.versioned("js/jquery.validationEngine.js")"></script>
<script src="#routes.Assets.versioned("js/jquery.validationEngine-en.js")"></script>
<script src="#routes.Assets.versioned("js/fastclick.js")"></script> <!-- Eliminating the 300ms click delay on mobile browsers -->
<script src="#routes.Assets.versioned("js/plugins.js")"></script>
<script src="#routes.Assets.versioned("js/scripts.js")"></script>
#scalajs.html.scripts("client", routes.Assets.versioned(_).toString, name => getClass.getResource(s"/public/$name") != null)
After this their is a request (which works) to scala.js which add the code above to the html structur at main.scala.html.
Now the adding sequence of my scala.js
val child = place.appendChild(Waiting.spinner.render)
Ajax.get(url(s"list/article/random?size=$size"),withCredentials = true).map{ xhr =>
place.removeChild(child)
val articleSeq = upickle.default.read[Seq[SharedArticle]](xhr.responseText)
val box = WidgetSingleArticleSlider.toHtml( title, articleSeq, addToCartText )
place.appendChild( box.render )
}
The problem is, that this added code is not transformed to a bxSlider. Also I try to restart it again as a bxSlider added as a script at WidgetSingleArticleSlider with:
$('.vertical-bx-1').bxSlider({
minSlides: 3,
slideMargin:0,
nextText: '<i class="arrow_carrot-right"></i>',
prevText: '<i class="arrow_carrot-left"></i>',
pager: false,
}));
The result is still only html. Asking for the loaded plugin results in undefined.
This is the code which was added after call:
<div class="widget wg-specials store-alt box-with-pager mobile-collapse"><h3
class="wg-title mobile-collapse-header store-alt">specials</h3>
<div class="wg-body mobile-collapse-body">
<ul id="tium" class="vertical-bx-1">
<li class="wgsp-item"><a href="#">
<figure><img src="/thumbnail/width/200/nothing"></figure>
</a>
<p class="wgsp-title">Wiesenkerbel Saatgut</p>
<p class="wgsp-price">2.34 EUR</p>
<div class="row no-gutter">
<div class="col-xs-12 text-center"><a class="btn btn-third-col" href="#">addToCart</a>
<div class="gap-30"></div>
</div>
</div>
</li>
<li class="wgsp-item"><a href="#">
<figure><img src="/thumbnail/width/200/nothing"></figure>
</a>
<p class="wgsp-title">Vogelmiere Saatgut</p>
<p class="wgsp-price">2.34 EUR</p>
<div class="row no-gutter">
<div class="col-xs-12 text-center"><a class="btn btn-third-col" href="#">addToCart</a>
<div class="gap-30"></div>
</div>
</div>
</li>
</ul>
</div>
<script>
jQuery('#tium').bxSlider();
if (window.jQuery === undefined) window.$ = window.jQuery = jQuery;
$(document).ready(function () {
$('.vertical-bx-1').bxSlider().reloadSlider();
$('#tium').bxSlider().reloadSlider();
$('.vertical-bx').bxSlider({
minSlides: 3,
slideMargin: 0,
nextText: '<i class="arrow_carrot-right"></i>',
prevText: '<i class="arrow_carrot-left"></i>',
pager: false
});
});
</script>
</div>
Solution found. No problem with scala.js it was jquery.
https://github.com/stevenwanderski/bxslider-4/issues/605
var j = jQuery.noConflict();
I added this line to my code and all worked fine.

AmpersandJs: Render sub-view

getting into AmpersandJs, and having a big showstopper by not figuring out why my sub-view-form isn't rendering it's markup.
My MainView.render, works as should:
render: function() {
BaseView.prototype.render.apply(this, arguments);
this.collectionView = this.renderCollection(this.collection, HSEventView, '.item-container');
this.renderSubview(new HSEventEditView({
action: 'create'
}), '.create-event');
return this;
},
Next, my SubView.render (HSEventEditView):
render: function () {
this.renderWithTemplate();
this.form = new EditForm({
el: this.query('.edit-form'),
submitCallback: function (data) {
debug('submit', data);
}
});
this.registerSubview(this.form);
debug('render.form.el', this.form.el)
}
And finally my FormView:
module.exports = FormView.extend({
initialize: function() {
debug('initialize', this.el)
},
autoRender: true,
fields: function () {
debug('fields!')
var fields = [
new InputView({
label: 'Name',
name: 'name',
value: utils.getDotted(this, 'model.name'),
placeholder: 'Name',
parent: this
})
];
debug('fields', fields)
}
});
The MainView and SubView renders fine, but the 'div.edit-form' DOM-node, where the form markup should be, is empty.
I have tried all variations of including a subview I could dig up, but obviously I am blind to something.
Thanks!
PS! Here is the rendered markup:
<section class="page">
<h2>Events collection</h2>
<hr>
<div class="tools">(Tools comming...)</div>
<hr>
<div class="item-container events">
<div class="item event">
<h3>Event: <span data-hook="name">Event 1</span></h3>
</div>
</div>
<hr>
<div class="create-event">
<div class="item event">
<h3>Create event: <span data-hook="name"></span></h3>
<div class="edit-form"></div>
</div>
</div>
</section>
Since fields is a function, you need to return the fields. In your Formview:
fields: function () {
debug('fields!')
var fields = [
new InputView({
label: 'Name',
name: 'name',
value: this.model.name,
placeholder: 'Name',
parent: this
})
];
debug('fields', fields)
// need to return the fields you've declared
return fields;
}