I Have some script, that takes element, but i cant find how to get it from react component. At least, i can get element after rendering, but now i have another problem - cant make event on button, coz i need SignatureObj
var SignaturePad = require('signature_pad');
var SignatureWidget = React.createClass({
_handleClear: function(e, SignatureObj) {
SignatureObj.clear();
},
_getSignature: function(canvas) {
return new SignaturePad(canvas);
},
componentDidMount: function() {
var wrapper = this.getDOMNode(),
canvas = wrapper.querySelector('canvas'),
SignatureObj = this._getSignature(canvas);
},
render: function() {
var canvas = React.createElement('canvas');
return (
<div>
{canvas}
<button>Clear</button>
</div>
);
}
});
Finally, i need to get something like this
render: function() {
var canvas = React.createElement('canvas'),
>> canvasEl = canvas.getElement(),<< magic
SignatureObj = this._getSignature(canvasEl);
return (
<div>
{canvas}
<button onClick={this._handleClear.bind(this, SignatureObj)}>Clear</button>
</div>
);
}
first some side notes, getDOMNode is deprecated, u should use findDOMNode, further u don't need to use create element within the render, because if you use the jsx syntax which u do it will be converted to the syntax u are using (createlement ..etc .. under the hood)
for your problem about selecting the element:
React.findDOMNode(this.refs.findMe)
<-- makes u find the node or as u call it :D (Magic)
render: function() {
return (
<div>
<canvas ref='findMe'></canvas> <------- magic
<button>Clear</button>
</div>
);
}
Hope this helps!
some good reads:
refs:
https://facebook.github.io/react/docs/more-about-refs.html
jsx:
https://facebook.github.io/react/docs/jsx-in-depth.html
i used this way to add event
componentDidMount: function() {
var pad = this.refs.pad.getDOMNode(),
saveButton = this.refs.save.getDOMNode(),
clearButton = this.refs.clear.getDOMNode(),
SignatureObj = this._getSignature(pad);
clearButton.onclick = this._handleClear.bind(this, SignatureObj);
saveButton.onclick = this._handleSave.bind(this, SignatureObj);
},
Related
I'm currently having a problem when trying to send an action from a child element to its parent element. I want to change the state of the MessagingContainer when a thread is clicked to mark that thread as the active thread. So when the thread (ThreadElement) is clicked, it needs to send to its parent (ThreadList), which then sends to its parent (MessagingContainer) in order for the Messaging Container to update the state.
Firstly, is this the right approach, RE: state and modifying state?
Secondly, I can't seem to get this working. I'm getting a persistent error of TypeError: undefined is not an object (evaluating 'this.props').
I've omitted the messages part of the code below so only the threads is visible.
var ThreadElement = React.createClass({
render: function() {
console.log('ThreadElement');
console.log(this.props);
var threadParticipantsNames = this.props.thread.participants.map(function(participant) {
var participantName;
if (participant.user) {
participantName = participant.user.metadata.first_name;
} else {
participantName = 'Anonymous';
}
return (
<span key={participant.id}>
{participantName}
</span>
);
});
return (
<div key={this.props.thread.id} onClick={this.props.handleActiveThreadChange}>
{threadParticipantsNames}
</div>
);
}
});
var ThreadList = React.createClass({
render: function() {
console.log('ThreadList');
console.log(this.props);
var threadNodes = this.props.threads.map(function(thread) {
return (
<ThreadElement thread={thread} key={thread.id} handleActiveThreadChange={this.props.handleActiveThreadChange} />
);
});
return (
<div className="threadList">
{threadNodes}
</div>
);
}
});
var MessagingContainer = React.createClass({
handleActiveThreadChange: function() {
console.log('MessagingContainer handleActiveThreadChange called.');
},
getInitialState: function() {
return {
activeThread: 0,
data: threadsJSON
};
},
render: function() {
console.log('MessagingContainer');
console.log(this.props);
return (
<div>
<ThreadList threads={this.state.data.threads} handleActiveThreadChange={this.handleActiveThreadChange} />
<MessageList thread={this.state.data.threads[this.state.activeThread]} />
</div>
);
}
});
The console gives the below output, if that helps. The MessagingContainer and ThreadList console.log()s seem to work, so does this suggest the issue is in the ThreadElement class?
[Log] MessagingContainer
[Log] {}
[Log] ThreadList
[Log] {threads: Array, handleActiveThreadChange: function}
[Error] TypeError: undefined is not an object (evaluating 'this.props')
Thanks!
From what I can see, I think the problem is your .map function in the ThreadList component. Your context has changed for this since you're inside the map function. You should use .bind or a local that = this variable to save the right context:
var threadNodes = this.props.threads.map(function(thread) {
return (
<ThreadElement thread={thread} key={thread.id} handleActiveThreadChange={this.props.handleActiveThreadChange} />
);
}).bind(this);
or
var that = this;
var threadNodes = this.props.threads.map(function(thread) {
return (
<ThreadElement thread={thread} key={thread.id} handleActiveThreadChange={that.props.handleActiveThreadChange} />
);
});
Strange problem with marked executed within my React component.
Has been working, but cannot see why it's stopped.
This is my React component
** #jsx React.DOM */
var React = require('react');
var marked = require('marked');
var Panel = require('react-bootstrap').Panel;
var Highlight = require('highlight.js');
var Markdown = React.createClass({
componentWillMount:function( ){
marked.setOptions({
highlight: function (code) {
return Highlight.highlightAuto(code).value;
},
sanitize: true
});
},
render: function () {
var rawMarkup;
if (_.isString(this.props.content)) {
rawMarkup = marked(this.props.content);
}
else if (_.isArray(this.props.content)) {
rawMarkup = marked(this.props.content.join("\n"));
}
return (
<div>
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
);
}
});
exports.Markdown = Markdown;
Tracing it through, the problem appear to lie here:
(this is extract of marked js)
// heading
if (cap = this.rules.heading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'heading',
depth: cap[1].length,
text: cap[2]
});
continue;
}
Where this.rules.heading == /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
and src == "#heading"
Nothing is found.
I have updated npm packages, but don't see how this would have stopped working?
Any ideas?
This is a section of my view in which I want the result to show.
Can any one solve this problem?
When this.waitlist works, it should return the container like div#sntq-waitlist but it gives object[ ] instead.
Can anyone tell me why this is?
JavaScript
initLiveWaitList: function() {
this.waitlist_ = $('sntq-waitlist');
this.daily_status_ = $('sntq-daily_status');
this.waiting_ = $('sntq-waiting');
this.seated_ = $('sntq-seated');
this.oneFour_ = $('sntq-one-four');
this.fiveSix_ = $('sntq-five-six');
this.seven_ = $('sntq-seven');
this.running_ = true;
this.loadWaitList_();
this.intervalId_ = this.loadWaitList_.periodical(1200000, this);
window.addEventListener('focus', function() {
if (!this.running_) {
this.loadWaitList_();
this.intervalId_ = this.loadWaitList_.periodical(1200000, this);
}
}.bind(this));
window.addEventListener('blur', function() {
clearInterval(this.intervalId_);
this.running_ = false;
} .bind(this));
},
View
<div id="sntq-daily_status">
<div class="loading"></div>
</div>
I donĀ“t think I completely understood your question, but to me it looks like you are using jQuery to get the containers at the top of your code.
If this is the case you are probably just missing the ID selector.
Try to change the code to
this.waitlist_ = $('#sntq-waitlist');
this.daily_status_ = $('#sntq-daily_status');
//[...]
(note the "#" selector if you want to look for elements by ID, which seems to be the case in your example).
I'm trying to dynamically generate alert components in React-Bootstrap at runtime by instantiating the components from Javascript classes. I'm doing this because there are lots of alerts to show and because Javascript classes are more succinct to create.
My attempts to do this are not working. I'm not sure whether the problem generally applies to React or just to React-Bootstrap. However, the error occurs in react.js, which throws the following:
TypeError: undefined is not a function
The throw occurs in the alert.getComponent() call in the following JSX file:
/** #jsx React.DOM */
var Alert = ReactBootstrap.Alert;
var AlertDismissible = React.createClass({
getInitialState: function() {
return {
isVisible: true
};
},
render: function() {
if(!this.state.isVisible)
return null;
var message = this.props.message;
if(this.props.code !== null)
message = message +'(Code '+ this.props.code +')';
return (
<Alert bsStyle={this.props.level} onDismiss={this.dismissAlert}>
<p>{message}</p>
</Alert>
);
},
dismissAlert: function() {
this.setState({isVisible: false});
}
});
function AlertNotice(level, message, code) {
this.level = level;
this.message = message;
this.code = code || null;
}
AlertNotice.prototype.getComponent = function() {
// What should go here? Using React.createClass() doesn't help
return (
<AlertDismissible level={this.level} message={this.message}
code={this.code} />
);
};
function SuccessAlert(message) {
AlertNotice.call(this, 'success', message);
}
SuccessAlert.prototype = Object.create(AlertNotice);
SuccessAlert.prototype.constructor = SuccessAlert;
/* ...more kinds of alerts... */
function ErrorAlert(message, code) {
AlertNotice.call(this, 'danger', message, code);
}
ErrorAlert.prototype = Object.create(AlertNotice);
ErrorAlert.prototype.constructor = ErrorAlert;
var SomethingWithAlerts = React.createClass({
render: function() {
var alerts = [
new ErrorAlert("Goof #1", 123),
new ErrorAlert("Goof #2", 321)
].map(function(alert) {
// react.js throws "TypeError: undefined is not a function"
return alert.getComponent();
});
return (
<div>{alerts}</div>
);
}
});
var TestComponent = (
<div>
<SomethingWithAlerts />
</div>
);
React.renderComponent(
TestComponent,
document.getElementById('content')
);
The Alert component comes from the React-Bootstrap library. The div components seem extraneous but I found them necessary to satisfy the react framework. In reality, I'll be storing the AlertNotice instances in react state and then generating react nodes from them.
What is the proper way to go about this?
Here's a hint. If I replace return alert.getComponent(); with the following hardcoded alert, the AlertDismissible components render without error (in duplicate) but I get a warning:
return (
<AlertDismissible level="danger" message="Goof" code="777" />
);
The following is the warning message I get with the above replacement, including a link that explains I should set key= to a unique for each alert:
Each child in an array should have a unique "key" prop. Check the render method
of SpecimenSetManager. See http://fb.me/react-warning-keys for more information.
However, if I simply replace the code inside of AlertNotice.prototype.getComponent with the above hardcoded alert, I get the same TypeError message as before.
For completeness, here is my HTML source. This is react and react-boostrap v0.11.1
<html>
<head>
<script src="lib/react.js"></script>
<script src="lib/react-bootstrap.js"></script>
<script src="lib/JSXTransformer.js"></script>
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body>
<div id="content"></div>
<script src="components.js" type="text/jsx"></script>
</body>
</html>
I solved the problem. The solution was to create a special react component that represents a set of alerts. Apparently it is only possible to reference automatic or object variables in component parameters from within the React.createClass() definition. Perhaps this is a syntactic constraint of JSX rather than a logical constraint of react.
I don't understand why this solution works. I would like to understand so that I don't have to deal with similar problems again in the future. If you can explain the general principle I'm violating and the general principle that should be followed instead -- something more insightful than what I've stated here -- then I'll mark your response as the "answer" to this question. I'd like to know how much flexibility I really have.
Here's the code that works, including a new AlertSet component:
/** #jsx React.DOM */
function AlertNotice(level, message, code) {
this.level = level;
this.message = message;
this.code = code || null;
}
function SuccessAlert(message) {
AlertNotice.call(this, 'success', message);
}
SuccessAlert.prototype = Object.create(AlertNotice);
SuccessAlert.prototype.constructor = SuccessAlert;
/* ...more kinds of alerts... */
function ErrorAlert(message, code) {
AlertNotice.call(this, 'danger', message, code);
}
ErrorAlert.prototype = Object.create(AlertNotice);
ErrorAlert.prototype.constructor = ErrorAlert;
var Alert = ReactBootstrap.Alert;
var AlertDismissible = React.createClass({
getInitialState: function() {
return {
isVisible: true
};
},
render: function() {
if(!this.state.isVisible)
return null;
var message = this.props.message;
if(this.props.code !== null)
message = message +'(Code '+ this.props.code +')';
return (
<Alert bsStyle={this.props.level} onDismiss={this.dismissAlert}>
<p>{message}</p>
</Alert>
);
},
dismissAlert: function() {
this.setState({isVisible: false});
}
});
var AlertSet = React.createClass({
render: function() {
var alerts = this.props.alerts.map(function(alert, i) {
return (
<AlertDismissible key={"alert-"+i} level={alert.level}
message={alert.message} code={alert.code} />
);
});
// component must be a single node, so wrap in a div
return (
<div>{alerts}</div>
);
}
});
var SomethingWithAlerts = React.createClass({
render: function() {
var alerts = [
new ErrorAlert("Goof #1", 123),
new ErrorAlert("Goof #2", 321)
];
return (
<AlertSet alerts={alerts} />
);
}
});
// TestComponent returns a single node, so doesn't need a div
var TestComponent = (
<SomethingWithAlerts />
);
React.renderComponent(
TestComponent,
document.getElementById('content')
);
Just started with knockout and need to implement page change warning. Following is the code snippet. I just need an alert pop up as warning if any change is made on the page.
function parseViewModel() {
var viewModel = JSON.parse(getState());
viewModel.checking = ko.observable(false);
viewModel.Slider = new ko.observable(100 - viewModel.Slider);
viewModel.CausalsList = buildHierarchy(viewModel.Causals);
viewModel.Causals["-1"] = "Total Marketing Budget";
viewModel.GeographiesList = ko.observableArray(gl);
viewModel.Geographies["0"] = "All Geographies";
viewModel.ProductsList = ko.observableArray(pl);
viewModel.Products["0"] = "All Products";
.
.
.
return viewModel;
}
function bindModel() {
model = parseViewModel();
ko.dirtyFlag = function (root, isInitiallyDirty) {
var result = function () { },
_initialState = ko.observable(ko.toJSON(root)),
_isInitiallyDirty = ko.observable(isInitiallyDirty);
result.isDirty = ko.computed(function () {
return _isInitiallyDirty() || _initialState() !== ko.toJSON(root);
});
result.reset = function () {
_initialState(ko.toJSON(root));
_isInitiallyDirty(false);
};
return result;
};
model.dirtyFlag = new ko.dirtyFlag(model);
model.isDirty.subscribe(function () {
alert("Page change warning!");
});
ko.applyBindings(model, $('#const').get(0));
ko.applyBindings(model, $('#buttonDiv').get(0));
}
Referred Ryan Niemeyer's blog. Unfortunately, it's not working anymore. Any insights please?
You would want to subscribe to model.dirtyFlag.isDirty in your case rather than model.isDirty.
One way to do is by using customBinding. I'm not that familiar with KO either but this might be something you're interested on.
Basically you would do is :-
ko.bindingHandlers.myFunction = {
update : function(){
//do something
}
}
http://knockoutjs.com/documentation/custom-bindings.html
And call it on your element using :-
<h1 data-bind="myFunction:{}"></h1>
Also, a jsfiddle to show how it works. (If you change the value of the First Name and focus out of it then the customBinding gets triggered. )
http://jsfiddle.net/3vuTk
Not sure if it's the best practice though.