React-router: component undefined - ruby-on-rails

I've been running through the react-router tutorial found here and I'm currently puzzled...
React-router doesn't recognise my component.
(I'm using React.js with Rails)
Here's the code:
var DefaultRoute = ReactRouter.DefaultRoute;
var Link = ReactRouter.Link;
var Route = ReactRouter.Route;
var RouteHandler = ReactRouter.RouteHandler;
var App = React.createClass({
getInitialState: function () {
return {
showTags: false,
current_user: this.props.current_user
};
},
_handleToggleTags: function() {
this.setState({
showTags: !this.state.showTags
})
},
render: function () {
return <div>
<Header
onToggleTags={ this._handleToggleTags }
user={this.props.current_user}
/>
<RouteHandler/>
<div id="images">
<ImageBox/>
</div>
</div>;
}
});
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="tags" handler={TagsBox}/>
</Route>
);
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
If I move TagsBox before App it works, though nobody else seems to be doing this. What am I missing?
If it makes a different, the current structure of my components is:
app.js.jsx
Tags
_tags_box.js.jsx

In your position it seems best to run the router once all scripts are loaded.
Try wrapping the run method in this code:
document.addEventListener("DOMContentLoaded", function() {
ReactRouter.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
}

Related

React / Rails : Append dynamically element to DOM

Currently following facebook tutorial on React (react_tuto).
I don't understand how 2 components can communicate so that on "submit a comment button" it appends dynamically the "comment list".
currently, comment are created on server but appears on page only when page refreshed
how can the comment appear on submit button?
This i my AddComment component
var AddComment = React.createClass({
getInitialState: function(){
return {
content: this.props.content,
adrien: "before"
}
},
handleKeyUp: function(e) {
this.setState({
content: this.refs.addComment.getDOMNode().value,
})
},
handleValidation: function() {
var that = this
$.ajax({
type: "POST",
data: {comment: { content: that.state.content } },
url: Routes.create_comment_path({format: 'json'}),
success: function(data) {
that.setState({
content: "",
adrien: "after"
})
}
})
},
render: function(){
return (
<div>
<textarea onKeyUp={this.handleKeyUp} value={this.state.value} ref="addComment"></textarea>
<button onClick={this.handleValidation}>submit</button>
</div>
)
}
})
This is my CommentList component:
var CommentList = React.createClass({
render: function() {
return (
<div>
{this.props.comments.map(function(comment){
return <CommentListElement key={comment.id} comment={comment} />;
})}
</div>
);
}
});
You need a common parent component for communication between different components.
I have updated you example a bit to include common parent component CommentSystem
Note: I have removed ajax call to just show the communication between component.
Check below link.
https://jsfiddle.net/j4yk3pzc/15/
Extra Info:
In react we store states on parent component and pass them down to children. Along with state we also pass actions to manipulate data down to the children. When child component want's to update data passed to it from parent, then it fires the action passed from the parent. This is called Data down action up approach. Data is passed from parent to child to grandchild. While actions are propagated from grandchild to child to parent.
If you don't want to create the parent component then you can use some Publish / Subscribe or EventEmitter based system to communicate between children having no common parent.
Reference:
http://ctheu.com/2015/02/12/how-to-communicate-between-react-components/
Code:
var CommentSystem = React.createClass({
getInitialState: function() {
return {
comments: []
}
},
addComments: function(comment) {
var comments = this.state.comments;
comments.push(comment);
this.setState({comments: comments})
},
render: function() {
return (
<div>
<AddComment addComments={this.addComments}/>
<CommentList comments={this.state.comments}/>
</div>
)
}
})
var AddComment = React.createClass({
getInitialState: function(){
return {
content: this.props.content,
adrien: "before"
}
},
handleKeyUp: function(e) {
this.setState({
content: this.refs.addComment.getDOMNode().value,
})
},
handleValidation: function() {
var that = this;
this.props.addComments(this.state.content);
},
render: function(){
return (
<div>
<textarea onKeyUp={this.handleKeyUp} value={this.state.value} ref="addComment"></textarea>
<button onClick={this.handleValidation}>submit</button>
</div>
)
}
})
var CommentList = React.createClass({
render: function() {
return (
<div>
{this.props.comments.map(function(comment){
return <CommentListElement key={comment.id} comment={comment} />;
})}
</div>
);
}
});
var CommentListElement = React.createClass({
render: function() {
return (
<div>{this.props.comment}</div>
)
}
})
React.render(<CommentSystem/>, document.getElementById('container'));
Hope this helps.

react-router - no component rendered on hash change

I am using Rails with react gem and react-router.js inside assets. I am using webpack in order to use require
I have my routes inside app.js:
var Router = require('react-router').Router;
var Route = require('react-router').Route;
var Link = require('react-router').Link;
var ReactDOM = require('react-dom');
var browserHistory = require('react-router').browserHistory;
ReactDOM.render((
<Router history={browserHistory}>
<Route path="/" component={Welcome}>
<Route path="hello" component={Hello}/>
<Route path="welcome" component={Welcome}/>
<Route path="about" component={About}/>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.getElementById('root'));
other.es6.jsx:
var Hello = React.createClass({
render: function () {
return (
<div>
<h3>Hello component</h3>
About
</div>
);
}
});
var Welcome = React.createClass({
render: function () {
return (
<div>
<h3>Welcome component</h3>
Hello
</div>
);
}
});
var About = React.createClass({
render: function () {
return (
<div>
<h3>About component</h3>
Welcome
</div>
);
}
});
var NoMatch = React.createClass({
render: function () {
return (
<h3>No Match</h3>
);
}
});
When I visit controller_name/index it renders by default the 'Welcome component' text with link to '#hello' but when clicking, it does not do anything. It's still saying 'welcome component'
What did I do wrong?
You are rendering only welcome content not any child component. I hope this will fix it.
var Welcome = React.createClass({
render: function () {
if(this.props.children){
return this.props.children
}else{
return (
<div>
<h3>Welcome component</h3>
Hello
</div>
);
}
}
});

React.NET uncaught TypeError: undefined is not a function

I am trying to learn ReactJs and found React.NET.
Followed the tutorial on the author's website with the only change being an MVC 5 app instead of MVC 4.
Here is the jsx:
/** #jsx React.DOM */
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.props.data} />
<CommentForm />
</div>
);
}
});
React.renderComponent(
<CommentBox data={data} />,
document.getElementById('content')
);
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function (comment) {
return <Comment author={comment.Author}>{comment.Text}</Comment>;
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
});
var data = [
{ Author: "Daniel Lo Nigro", Text: "Hello ReactJS.NET World!" },
{ Author: "Pete Hunt", Text: "This is one comment" },
{ Author: "Jordan Walke", Text: "This is *another* comment" }
];
It gives this error:
Uncaught TypeError: undefined is not a function
Any clues on this one?
Regards.
There are three steps in the snippet.
First, define the CommentBox:
var CommentBox = React.createClass...
Second, render the CommentBox and the CommentList:
React.renderComponent...
Third, define the CommentList:
var CommentList = React.createClass...
So, the problem is that the CommentList is rendered before the CommentList is defined. If the last two steps were switched around then it would work fine. The CommentList class needs to be defined before it can be rendered.
CommentForm is also defined in the wrong place - it needs to be defined before it's referred to. The React tutorial has it the wrong way round: http://facebook.github.io/react/docs/tutorial.html
The correct order for the definition of the classes in the Javascript is:
var Comment = React.createClass
...
var CommentList = React.createClass
...
var CommentForm = React.createClass
...
var CommentBox = React.createClass
...
I had this happen whilst working through the tutorial and found that declaring the var data = [...] at the top of the jsx script resolved the issue. So it would appear that the engine is not hoisting variables properly?

Multiple ViewModels Knockout with JQuery

I Have this Fiddle
It is working perfectly in the fiddle, but as soon as i put everything in a ASP.NET MVC4 Application the second ViewModel is not loaded!
This normally is only when i add the following Script Tag to my Project
<script src="../../Scripts/jquery.mobile-1.2.0.js" type="text/javascript"></script>
Do i need some JQuery Functions to load the second ViewModel or what did i wrong? ;)
Here is my code:
<form action="" data-bind=" template:{ 'if': loginVM, data: loginVM }">
//SomeCode
</form>
<form action="" data-bind=" template:{ 'if': startVM, data: startVM}">
//Some Code
</form>
<script type="text/javascript">
var masterViewModel = {
loginVM: ko.observable(),
startVM: ko.observable(),
projektUnterbrechen: ko.observable(),
logout : ko.observable(),
projectStartVM: ko.observable()
};
var LoginVM = function () {
var self = this;
self.mandant = ko.observable();
self.user = ko.observable();
self.password = ko.observable();
self.showDetails = function () {
if ((self.user() == "Gregor") && (self.password() == "gregrech")) {
masterViewModel.loginVM(null);
masterViewModel.startVM(new StartVM());
**//alert(masterViewModel.startVM()!=null) //==True**
}
else {
alert("Username oder Passwort falsch");
}
};
};
var StartVM = function () {
self = this;
**//alert(masterViewModel.startVM()!=null) //==False**
//Um weiterzumachen muss man eingeloggt sein
self.favoriten = ko.observableArray([
{
projectName: "Favorit1"
},
{
projectName: "Favorit2"
},
{
projectName: "Favorit3"
}
]);
//Die zuletzt verwendeten Projekte
self.zuletzt = ko.observableArray([
{
lastProjName: "Zuletzt1"
},
{
lastProjName: "Zuletzt2"
},
{
lastProjName: "Zuletzt3"
}
]);
self.showStart = function (projectName, data, event) {
masterViewModel.projectStartVM(new ProjectStartVM(projectName));
masterViewModel.startVM(null);
};
};
masterViewModel.loginVM(new LoginVM());
$(document).on('pageinit', function () {
ko.applyBindings(masterViewModel);
});
</script>
Thank you for your answers
EDIT:
I found out, that i get different Values if i compare my masterViewModel.startVM()!= null even if it has to be the same!
Maybe this helps you!
Please look at the comments with "**" in my Code to understand what i mean
Try to load viewmodel in ready event not pageinit event.
$(document).ready(function () {
ko.applyBindings(masterViewModel);
});

jquery close datepicker when input lose focus

I'm using datepicker inside my input , my last field is the datepicker input , after validating it i want to set focus on another input inside my form , but the problem is the datepicker is not closed even taht it does not have the focus..
how can I close the datepicker when i set the focus on another input field?
(I tried .datepicker("hide"); but it did not worked for me).
UPDATE:
this is my code:
$(function()
{ $( "#test_date" ).datepicker({
dateFormat: "dd/mm/yy"
});
});
//when i call my function:
$( "#test_date" ).datepicker("hide"); //---> this does not work!
Thank's In Advance.
Question Edited to work with the latest version of jqueryUI
JqueryUi auto-closes the datepicker when an element loses focus by user interaction, but not when changing focus with JS.
Where you are calling your function which removes focus from the input assigned a datepicker you also need to call:
$("#test_date ~ .ui-datepicker").hide();
This code is hiding the datepicker which is a sibling (~) of #test_date.
To be dynamic, and using the class assigned by jQueryui you can do:
$(".hasDatepicker").on("blur", function(e) { $(this).off("focus").datepicker("hide"); });
;(function() {
function eventOnFocusDP(e, par) {
if (par.ver == $.fn.jquery) {
if (this.tmr) clearTimeout(this.tmr);
par.lbl1.text(par.msgs[1]);
this.tmr = setTimeout(function() { par.inpNP.focus(); }, par.secs*1e3);
}
}
function eventOnFocusNP(e, par) {
if (par.ver == $.fn.jquery) {
par.lbl1.text(par.msgs[0]);
par.lbl2.text(par.msgs[2]);
}
}
function eventOnBlurNP(e, par) {
if (par.ver == $.fn.jquery) par.lbl2.text("");
}
function eventOnBlurHDP(e, par) {
if (par.ver == $.fn.jquery) {
$(this).off("focus").datepicker("hide");
}
}
function test(secs) {
this.ver = $.fn.jquery;
this.secs = (typeof secs)=='number'?secs:2;
this.msgs = [
'This will lose focus to box below '+this.secs+' seconds after it gains focus.',
'Losing focus in '+this.secs+' seconds!',
'Focus now on bottom box.'
];
this.inpDP = $('[name=datePicker]');
this.inpNP = $('[name=nextPicker]');
this.lbl1 = $('#dPMsg').text(this.msgs[0]);
this.lbl2 = $('#dPMsg2');
var par = this;
this.inpDP.datepicker({ dateFormat: "dd/mm/yy" })
.on('focus', function(e) { eventOnFocusDP.apply(this, [e, par]) });
this.inpNP.on('focus', function(e) { eventOnFocusNP.apply(this, [e, par]) });
this.inpNP.on('blur', function(e) { eventOnBlurNP.apply(this, [e, par]) });
$(document).on('blur', '.hasDatepicker', function(e) { eventOnBlurHDP.apply(this, [e, par]) });
return this;
}
function init() {
window.Test = test;
setTimeout(function() {
$(document).on('change', '.switcher, .switcher-ui', function(e) { if (window.Test) new Test(); });
$(jQueryUISwitcher).trigger('change');
}, 1e3);
}
if (document.readyState == "complete") init();
else jQuery(window).on('load', init);
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/JDMcKinstry/cfc32292cbbfa548fb9584db05b2b2fc/raw/4f16f7ee441dfb98aa166a2e84193b14574a46d1/jquery.switcher.js"></script>
<form action="javascript: void 0">
<input type="text" name="datePicker" id="dP" placeholder="mm/dd/yyyy" />
<label for="dP" id="dPMsg"></label>
<hr />
<input type="text" name="nextPicker" placeholder="tab to here" />
<label for="dP" id="dPMsg2"></label>
</form>
<hr />
<hr />
<hr />
Here's a modified solution that worked for me:
$(".hasDatepicker").each(function (index, element) {
var context = $(this);
context.on("blur", function (e) {
// The setTimeout is the key here.
setTimeout(function () {
if (!context.is(':focus')) {
$(context).datepicker("hide");
}
}, 250);
});
});
My version of js:
<script type="text/javascript"> $(function () {
$("#dtp1").on("dp.change", function (e) {
$('#dtp1').data("DateTimePicker").hide();
});
});
I hope it's help you
This worked for me:
$("#datepickerTo").datepicker({
onSelect: function () {
$(this).off( "focus" );
}
});

Resources