I have a custom element being used inside React. I want to be able to change attributes on the element from React. I also want to be able to change the same attributes from inside the element itself. Unfortunately, when the element changes its own attribute, this causes some odd side effects that I believe are related to React's virtual DOM being unaware that the attribute has changed.
To illustrate, assume we have a React render function that returns the following:
<my-component foo="bar"/>
And my-component has logic inside of it that, when the element is clicked, will change foo's value from bar to unicorn. Everything up to this point works as expected. The problem is that during the next render cycle, foo is not set back to bar. I want foo to be set back to bar.
My guess is that React's virtual DOM has bar as the cached value (it doesn't realize it has changed to unicorn) and therefore doesn't attempt to set it back to bar.
Is my understanding correct?
How do I make it so foo's value is set back to bar on the next render cycle?
You are correct about the virtual DOM. To make it behave the way you want, the custom element needs to be written in a way that supports it.
Think of this as being equivalent to controlling an <input>, where you would bind a handler to the input's onChange and either call event.preventDefault() to block any changes to the vlaue, or pass the new value back to the <input> to update the virtual DOM.
Therefore for this to work, the custom element needs to support a similar event handler.
Related
I have an custom component that serves as an input (in my application it does more things, but I've wanted to keep same structure so I've wrapped native input into component).
Then when user changes value of an input, I am calling closure action to format value provided by user (in example I am uppercasing it) and set it to some property (which should be visible for user in input).
Problem happens when I paste some lowercased string (for example abc), and then without deleting nor adding anything I just select everything and paste from clipboard (again abc). At second paste the formatting closure action is called, even setter of an property is called (I've tried computed property with custom set), but my component's input stays unformatted.
I've provided minimal Ember Twiddle to play with: https://ember-twiddle.com/5448bb455fd8732cc87f6ed8f2d44c12
The value is updated in action handler of application controller. At that handler, toUpperCase is called and result is set to a.
In the second call, since the a is not changed, value of my-input will not changed. So the component will not re-render. And pasted value will stay remained.
You can watch this situation by adding {{log (concat 'test' a)}} line to the application.hbs. It will printed only one time.
To make it work: Put the making uppercase logic to the my-input component. It will simply work. Have a look at this twiddle, you can implement similar component.
I've an HTML table generated by React render() which is tied to a websocket for realtime updates.
What I'm looking to do is attach a React event handler "onClick" to the cell which replaces the value in the cell with a custom piece of DOM such as some Bootstraps dropdown HTML so the user can update that cell.
I can use .getDOMNode() in the click event handler and then manipulate the DOM manually and insert the code, however if render() on this component was called due to a new updated state from a websocket event it would be overridden. If this race condition occurs, I need to inform the user instead of the DOM simply being replaced. I've just seen componentWillUpdate() though this still feels like I'm not using React correctly.
Is there a better approach ? It feels dirty to be manipulating the DOM and incorrect to change the state.
Updating internal component state is there for exactly this case. This component should be in charge of determining whether it is active or not. If you update state on the component when the click handler is triggered with something like active: true, then you trigger a re-render. In your render function add the additional DOM elements if active is true. Then you have three different possibilities that should be accounted for:
onBlur
onUpdate which can
be triggered in two ways. either way you'll likely want to set
active: false on state.
websockets - you will need to inform your
user here probably regardless of if the component is active or not
user - which will just update normally
Doing it this way means that React is always in full control of the DOM, which is a really good way to avoid issues with React.
I'm trying to add a Polymer UI to an existing HTML page which contains a form. I don't have control over the content of the page, only the header and footer, so I can't change the form to use Polymer elements rather than <input>. So instead I'm trying to rewrite the form using Javascript.
I'm finding that adding an is attribute to an existing element has no effect --- the element doesn't get upgtaded.
I presume that this is all happening at a point after which Polymer has scanned the DOM looking for is attributes, so it's not noticing my change. (Although creating a new element with an is attribute and adding it also doesn't work, which is kind of weird, because adding a Polymer custom element does work.)
Is there any way around this; such as telling Polymer when I add the new element so that it can be upgraded properly?
To use is=, you must be extending a native element. These are called type extension custom elements (http://www.html5rocks.com/en/tutorials/webcomponents/customelements/#usetypeextension).
In general, I don't believe adding the is= attribute at a later time has any effect on upgrading the element. The element needs to be declared up front with is= (e.g. <input is="core-input">) or instantiated dynamically using the special version of createElement:
var input = document.createElement('input', 'core-input');
In the declared case, this is the parsers signal to alter the prototype of the element when it's seen. In the JS case, that's done at creation time. If you just use el.setAttribute('is', 'core-input'), the element's prototype is already created by that point so it has no effect.
Say I have a JQuery object, el, that has selected an element. Is it legal, safe, and reasonable to call el.trigger("change") if the selected element is a DIV? What about other element types? For that matter, can I call el.change()?
The JQuery documentation for .change() says:
The change event is sent to an element when its value changes. This event is limited to <input> elements, <textarea> boxes and <select> elements.
It's not clear to me what "limited" means here. It might be referring to the fact that these are the only three element types that will produce these events automatically, but it could instead mean that other elements aren't allowed to.
Empirically, Chrome v28 seems to allow it, but I want to know if I can expect it to work in general.
Goal
I have a pseudo-control that's composed of a set of buttons and spans wrapped in a div. Each instance of the control maintains and manages a value, which is modified by clicking the control's buttons. When the value changes, I need to send an event out from the div so that the rest of the page can react. I don't want to listen for the click events outside the control, since that couples the surrounding code to the controls' internals and not all clicks change the value.
I could create a new event name, but the built-in "change" event seems like conceptually correct, so I'd rather use it if I can. As an added bonus, my page already a "change" handler bound the right place with the right behavior (because I have some input and select controls on the page, too).
I need to support IE8 and up, in case the answer varies by browser make and version.
There are no restrictions, you can trigger any event type you like on any HTML element.
The jQuery documentation is simply telling you that change is only automatically triggered on <input>, <textarea> and <select>
I am creating a site that allows viewing and editing the contents of the 'src-div' contents within the 'edit-div.' I am not editing the src-div directly, because its thumbnailed using css zoom property.
I have considered using knockout.js to bind both elements to an observable. Currently, I have implemented the feature with jquery .html() function: simply set edit-div innerhtml to src-div innerhtml on 'select', and reverse the process after changes are made to edit-div to update the src-div.
I am wondering if I really need 2 divs here, or if there is some way to actually view the same element twice on a page, and any changes made will automatically reflect in both 'views,' elimiating the need to copy innerhtml property back and forth between two elements.
essentially, this is like a mirror effect, without the flip.
the closest thing I found so far is:
http://developer.apple.com/library/safari/#documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Reflections/Reflections.html
Any recommended practices for performing this task are appreciated.
(Almost) everything you see on a page has a counterpart in the DOM. Everything in the DOM gets exactly rendered one time (apart from pseudo-classes). And every node in the DOM can only have one parent (no exclusions).
Unfortunately you'll have to clone the specific node and add changes to both, as there is no copy & translate mechanism in the current CSS documentation.
If you're using jquery you can use one div and "clone" it. You can read this for more information.
http://api.jquery.com/clone/
If you set the class of the div to the same thing, you can have changes propagated to both. Then you can apply .addClass to the second div to apply a "reflected" affect (if that's your final goal).