Quill: Which method called when blot changed? - quill

I need to do something when text, wrapped with my own blot, changed.
From parchment documentation i got that method update will called when blot changes.
I try to use it in code, but this method does't called when text, wrapped with my blot, changes.
May be I use this method incorrect? Or I should use another method?

You should use text-change event:
this.quill.on('text-change', (range, oldRange, source) => {
// Returns the leaf Blot at the specified index within the document
let [leaf, offset] = this.quill.getLeaf(range.index); // Experimental API
if(leaf.domNode.nodeName === 'yourBlotTag') {
//Do something
}
}

Related

Should you create a custom eventWrapper component for react-big-calendar?

There is no documentation for adding a eventWrapper and I've seen a few comments saying it's not meant to be overwritten. Should we be using this or trying to create custom eventWrapper component to override this exsisting one?
For me I don't want the .rbc-event-label also want to dynamically in JS change the styling. Or should I be just changing things in the CSS?
You can dynamically apply additional classes and styling to your events by using the eventPropGetter property. This property takes a function that should return an object of class names and styles to be applied to an event (automatically added to the eventWrapper).
const eventRenderProps = (event, start, end, isSelected) => {
let result = {};
// Code to conditionally add 'className' or 'style' to the result
return result; // {className?: String, style?: Object}
}
//
<MyCalendar eventPropGetter={eventRenderProps} />
It's important to note that this method is called on every displayed event, and will get called again on each as an event is selected or changed/updated. Also important to note that className is to be a String, and not an object, so if you require several classes you will need a space delimited list of class names.

Calling methods in Froala wysiwyg editor for React

I'm using a rich text editor called Froala, in its React version. The docs are intended for the JQuery one. From the little that is written about React, i found these instructions:
Events and Methods
Events can be passed in with the options, with a key events and object where the key is the event name and the value is the callback function.
options: {
placeholder: "Edit Me",
events : {
'froalaEditor.focus' : function(e, editor) {
console.log(editor.selection.get());
}
}
}
Using the editor instance from the arguments of the callback you can call editor methods as described in the method docs. Froala events are described in the events docs.
I understand how i can use events, but not calling methods. Does it mean that i can access the editor instance, only from an event? Can someone clarify this? For instance, i would like to use the html.insert() method, as described here:
$('.selector').froalaEditor('html.insert', 'foo bar', true);
How would that be used with the Froala React component?
In case anybody is interested, i implemented an easy workaround:
I use the "initialized" event, just to get the Froala instance, and place a reference to it in my class::
'froalaEditor.initialized' : (e, editor)=> {
this.froalaInstance = editor;
}
Now i can access the Froala instance...
If anyone is still interested in how to achieve this take a look at
https://froala.com/wysiwyg-editor/docs/framework-plugins/react/
It's pretty straight forward to define methods in the config object.

React 15.4.2 Cannot read property 'ref' of null

I try get access to method of child component.
It look like that:
1.Called method by ref name of component and then method
Form.js
this.ref.details.getDataFromComponent();
<Details
pointToShow={this.state.point}
ref="details"
/>
Details.js
getDataFromComponent() {
//do my stuff get state and connect to get data for component Details
}
All the time I have "Uncaught TypeError: Cannot read property 'ref' of null"
React 15.4.2
To access refs of a component, you need to use this.refs, not this.ref.
However, this does not seem to be the issue here, as the error clearly says that this is null when you are trying to access it. To determine why this is we need to see more of your code.
You should also look into defining refs using the ref callback attribute instead of the way you are doing it, as this syntax is no longer recommended and may be removed in future releases.
As Timo has mentioned to access an element using refs you should you should write this.refs...
According to the error you don't have access to this. Most probably you are calling this.ref.details.getDataFromComponent(); inside a method without access to this
For example you write :
callRef() {
this.ref.details.getDataFromComponent();
....
}
If so then you don't have an access to this there. You should bind your function with this.
You can either use arrow function to auto bind with this :
callRef = () => {
this.ref.details.getDataFromComponent();
....
}
Note: to use arrow function you need to use babel loader in your webpack configuration.
Or you can bind when calling the method.
For example you should call callRef() method inside jsx codes like this:
< ... onClick={this.callRef.bind(this)} />

How can I tell when this.setState exists in ES6?

I have been struggling with trying to migrate my React code from ES5 to ES6. As I have found out by now, this is no longer automatically bound which causes all sorts of hell.
I am trying to figure out by trial and error what objects are being passed around. So far I can find everything and adjust accordingly. However when it comes to this.setState I am having problems because it is not visible in console.log!!!! See screenshot in ES5:
and here is the same kind of code in ES6:
Please teach me how to fish i.e. help me figure out how to understand when an object has this.setState or not?
things i have tried
from googling around i understand you might be able to default bind everything by changing the base component. unfortunately this did not work when it came to this.setState. It looks identical to the ES5 version of this in console so I concluded that setState is still not being bound somehow
To oversimplify how this works in JS:
If you call a function as an object method (e.g., instance.foo()) then this refers to that object instance.
If you call a function by itself (e.g., foo()), then this is either undefined or the global object, depending on whether strict mode is in effect.
If you take a reference to an object method then call it, that means you're calling it by itself, even though it was originally an object method. (E.g., var bar = instance.foo; bar();.
Again, this is an oversimplification; MDN has details.
As this applies to React, and as explained in the React documentation on "Handling Events":
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
In your code, you render your RawInput as
<RawInput value={this.state.value} updateValue={this.updateValue}/>
You're passing a reference updateValue function in as a simple function, so this will not be bound within updateValue.
Basically, any time you pass a function as a React prop, unless you've bound it yourself, it's likely an error. The symptom is typically that this is undefined. In your code, it's a little more complicated:
this.props.updateValue(modifiedValue);
The RawInput's updateValue property is the unbound function App.updateValue, but because you're invoking it as this.props.updateValue, it's being called as if it were a method of this.props - so this refers to the RawInput's props. That's why your console.log is showing an object with only two properties (start and updateValue): it isn't that setState isn't bound or went away, it's that updateValue wasn't bound, so this isn't what you expect within updateValue.
To fix the issue, as the React docs explain:
Use a fat arrow function: updateValue={(value) => this.updateValue(value)}
Use the experimental property initializer syntax: Replace updateValue(modifiedValue) {...} with updateValue = (modifiedValue) => {...}.
Not mentioned in the React docs, but an approach I often use: Bind updateValue yourself. For example:
constructor(props) {
super(props);
this.updateValue = this.updateValue.bind(this);
}
you can replace console.log with this:
console.shallowCloneLog = function(){
var typeString = Function.prototype.call.bind(Object.prototype.toString)
console.log.apply(console, Array.prototype.map.call(arguments, function(x){
switch (typeString(x).slice(8, -1)) {
case 'Number': case 'String': case 'Undefined': case 'Null': case 'Boolean': return x;
case 'Array': return x.slice();
default:
var out = Object.create(Object.getPrototypeOf(x));
out.constructor = x.constructor;
for (var key in x) {
out[key] = x[key];
}
Object.defineProperty(out, 'constructor', {value: x.constructor});
return out;
}
}));
}
any way, regarding your question, you can add a method like this:
updateValue = () => {...}
in m POV - es6 is cool and great. React components by es6' classes are useless. stick with createClass and you'll be fine (and have mixins if you want!)
Try Object.prototype.hasOwnProperty(). For example:
var X = function() {};
X.prototype.setSomething = 'a';
var x = new X();
x.setSomething; // log 'a' here
x.hasOwnPrperty('setSomething') // log false here
In your case, just console.log(this.hasOwnProperty('setState')).
You have to bind your updateValue function with the component in order to have the correct context (this).
In your case, your parent class BaseComponent allows you to use the herited method _bind like that :
class App extends BaseComponent {
constructor(props){
super(props);
this.state={value:'start'};
this._bind('updateValue');
...

Binding to event handler that calls setState in ComponentDidMount produces warning

I'm using jQuery to create event bindings in a ReactJS component's componentDidMount function, which seems like the right place to do this.
$('body').on('defaultSearchContext.registerQueryEditor', (function(_this) {
return function(event, component) {
_this.setState({
queryEditors: _this.state.queryEditors.concat([component])
});
};
})(this));
This code isn't actually run on componentDidMount, it's simply setting up the binding that later calls setState when the event fires. However, this generates the following warning every time this event triggers, which pollutes my console with dozens of warnings:
Warning: setState(...): Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
I have tried moving the setState code to a separate function like onEvent and calling that from the binding in componentDidMount but the warning is still produced.
Ideally, I'd like to create the binding in the proper place, indeed, there is some issue with doing it in componentDidMount. If not, I'd like to know if it's possible to silence the warning, or whether I should perhaps file a bug for ReactJS itself. If it helps, I'm using ReactJS 0.14.3 (latest at this time).
This is similar to, but not the same as React Js onClick inside render. In that case, the solution is to return an anonymous function to onClick, but that doesn't seem applicable to my situation.
You are trying to coordinate events between independent components. This is a fairly standard thing to do, and it doesn't require DOM events. The standard practice for doing this in React is to use a store/dispatcher pattern like Redux or Flux (I personally prefer redux). However, if this is part of a larger, not-completely-React application, then this may not be possible. If it is just for a small piece of an React app, it may still be overkill.
All you need is an object to coordinate events. An event is just a collection of callbacks, possibly typed or keyed. This requires nothing more than an object shared between two places. DOM Events are overkill; jQuery is overkill. You just need to trigger a callback.
This is a VERY SIMPLE event coordinator.
let simpleEventCoordinator = {
callbacks: new Map(),
getHandler(eventKey) {
let handler = this.callbacks.get(eventKey);
if (!handler) {
handler = new Set();
this.callbacks.set(eventKey, handler);
}
return handler;
},
registerCallback(eventKey, callback) {
this.getHandler(eventKey).add(callback);
},
removeCallback(eventKey, callback) {
this.getHandler(eventKey).delete(callback);
},
trigger(eventKey, data) {
this.getHandler(eventKey).forEach(c => c(data));
}
Keep a map of callbacks, which will be nameOfEvent => callback(). Call them when asked. Pretty straightforward.
I know nothing about how your components are structured, but you said they are independent. Let's say they look like this:
React.render((
<div>
<QueryManager />
<button onClick={() => simpleEvent.trigger('event')}>{'Update'}</button>
</div>
), document.body);
This is all your component needs to handle this event
componentDidMount() {
simpleEvent.registerCallback('event', this.update);
}
componentWillUnmount() {
simpleEvent.removeCallback('event', this.update);
}
update() {
//do some stuff
}
I've put together a very simple codepen demonstrating this.
Looking at the source code of where that warning is coming from, it appears that if some reference is maintained before an update is about to happen, it throws that warning. So maybe the way your mixing the jQuery events and react is creating a memory leak? Its hard to say exactly because of the lack of surrounding code to your snippet what else could be going on.

Resources