Best way to dim/disable a div in Material-UI? - html

In my app, I have divs that I want to dim and disable mouse events for, depending on component state - for example, loading. The initial method I came up with is to have a helper function that returns an inline style for dimming an element and disabling pointer events on it, given a boolean value:
const disableOnTrue = (flag) => {
return {
opacity: flag ? 0.15 : 1,
pointerEvents: flag ? "none" : "initial"
}
}
and using it on elements as such:
{loading && {/** render a loading circle */}}
<div style={disableOnTrue(this.state.loading)}>{/** stuff to be dimmed & disabled while loading */}</div>
In the disabled div, there are Material-UI Buttons. However, it turns out that they don't care if pointerEvents are disabled on their parent div, and remain clickable, which is a big problem. So, on the Buttons I had to set disabled={loading}. Then, this dims the Buttons themselves, which unnecessarily compounds with the lowered opacity of disableOnTrue, meaning I would need to add some custom styling to ameliorate that; I want the entire div to be disabled, not for the Button to look especially disabled.
I've also tried using the Backdrop component from Material, but couldn't get it to dim anything but the entire viewport.
Before I implement any sort of hacky solution throughout my entire app, I figured I should ask here to see if there is a clean way to achieve this that I'm missing. I've looked for quite a while, but haven't found anything.

I split the concept of "disabling" into two functions:
const dimOnTrue = (flag) => {
return {
opacity: flag ? 0.15 : 1,
}
}
const disableOnTrue = (flag) => {
return {
pointerEvents: flag ? 'none' : 'initial'
}
}
to be used on divs that should be dimmed and inputs that should be disabled, respectively.

Related

Having trouble with jquery dynamic input and regex matching. Partially works

I have a dynamic input field where a user can add as many colors as he wants using an "Add" button.
The array works fine. Posts fine. My issue is with a some regex matching. Basically if a user enters one of the colors in the regex pattern a div container with another input shows. This works fine.
The issue:
User enters "purple" - no match, nothing shows. Good.
User enters "blue" - match, div shows. user deletes "blue" div disappears. Good.
User enters "red" - match, div appears. Good.
User enters "yellow" - no match, div disappears. Not Good.
Once the match has occurred I need the div to stay visible. What's happening though is it's removing the div if the next input is not a match.
$("#add").click(function(e){
$('input[name="item_color[]"]').keyup(function() {
var data = $(this).val();
var regx = /(blue|red|orange)/gmi;
if (data.match(regx)){
$("#divcolor").show();
}
else {
$("#divcolor").hide();
}
});
});
I've tried removing the
$("#divcolor").hide();
which somewhat works. except if the user goes back through the inputs and deletes the match that caused the div to show initially the div continues to show.
Basically I just need it to show the div if any match occurs in any of the inputs and hide the div if no matches occur. I really need the div to show/hide on keyup is the biggest thing.
Any help would be appreciated. I'm sure its something easy. I just can't wrap my mind around the logic.
You could solve the issue by checking all inputs each time you call the handler and set a var to true, if there is a match:
let matches = false;
$('input[name="item_color[]"]').each(function() {
if ($(this).val().match(regx)){
matches = true;
}
});
Furthermore the issue, that you mentioned in the comments, that the event handler isn't working when you define it outside the add handler, is related to the fact, that the inputs aren't created at the time of the definition. To prevent it you could attach the event listener directly to the body but add a selector to it:
$('body').on('keyup', 'input[name="item_color[]"]', function() {
Then the event listener is attached to an element that exists and the selector is used not before the listener is called.
Working example:
$("#add").click(function(){
$('#input-wrapper').append('<input name="item_color[]">');
});
$('body').on('keyup', 'input[name="item_color[]"]', function() {
let matches = false;
var regx = /(blue|red|orange)/gmi;
$('input[name="item_color[]"]').each(function() {
if ($(this).val().match(regx)){
matches = true;
}
});
if (matches){
$("#divcolor").show();
}
else {
$("#divcolor").hide();
}
});
#divcolor {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">Add</button>
<div id="input-wrapper">
<input name="item_color[]">
</div>
<div id="divcolor">
<p>div visible</p>
</div>

How to make a button to disable elements in a class

I am trying to create a filtering system for a portfolio site in wordpress (using the Divi Builder) and would love to be able to make a button/buttons to set elements with specific classes on a page to display: none when the button is clicked on.
If anyone has ideas on how this can be done that would be super appreciated.
Thanks
If you can use jQuery, the .show() and .hide() Functions work on jQuery objects.
For example $('.dataholder').hide().filter( (index,element) => $("body").innerHTML == "abc" ).show() will hide all nodes with class dataholder and then show those containing abc.
Otherwise you have to use something like
element = document.querySelector('#dataholder')
element.style.display = 'none'
Or
elements = document.querySelectorAll('.dataholder')
elements.forEach( element => element.style.display = 'none' )

is the renderProps pattern possible with polymer's lit-element?

There is a very useful pattern in react called the renderProps pattern (https://reactjs.org/docs/render-props.html) but I'm not sure if this is possible with lit-elements, due to the way the shadow dom isolates the css (meaning any css defined on the renderProp won't be carried into the shadow dom of the component with the renderProp).
Has anyone found a way around this, or a different pattern that enables the same use case as the renderProps pattern ?
Thanks !
EDIT: Here is an example that might make it clearer. Let's imagine a hover-menu component whose job is to display a menu on hover. This menu might need to know the position of the element hovered. And we obviously want to be able to render whatever we want inside it.
So we would like to be able to do something like that (renderMenuContent is a renderProp).
<hover-menu
.renderMenuContent="${(boundingClientRect) =>
html`<div>my menu content which could be positioned using ${JSON.stringify(boundingClientRect)}</div>`
}"
></hover-menu>
Turns out there is indeed no such easy solution as in React, again due to the isolation of the shadow dom.
The best solution is to create a component and use it in the renderProp (this way it can manage its own css classes).
In our example:
<hover-menu
.renderMenuContent="${(boundingClientRect) =>
html`<my-menu-content .boundingClientRect="${boundingClientRect}"></my-menu-content>`
}"
></hover-menu>
class MyMenuContent extends LitElement {
static get properties() {
return { boundingClientRect: { type: Object } };
}
static get styles() {
return css`.my-container { color: red }`;
}
render() {
return html`<div class="my-container">
can be positioned using ${JSON.stringify(this.boundingClientRect)}
</div>`;
}
}

Can I force the increment value on scroll for dijit.form.NumberSpinner?

I'm using the dijit.form.NumberSpinner() widget in a form for looking up indexed content. This works great in most cases—entering a number, using the arrow keys, and using the spinner buttons all respond in the right manner. However, on some browsers (notably Firefox), using the scroll wheel over the field increments the value by something > 1.
Is there a way to force the scroll increment on such a number field to be 1 across all browsers? The +3/-3 behavior is strongly undesirable for my application as the results are scrolled through in real time as the value is updated.
I am already using a custom widget derived from NumberSpinner so adding or over-riding a property should not be difficult if that is what is required, I just don't know what to change. The docs only say the increment should be 1 for arrow keys, they don't say anything about scrolling.
That's because it depends on what the event itself provides (= given by the browser). Currently it uses either the evt.wheelDelta or evt.detail property from the mousewheel event to determine the increment value. However, there are no standards yet and most implementations are using certain functions to normalize the scrolling speed.
If you use the following code in Firefox:
require(["dojo/ready", "dojo/mouse", "dojo/on", "dijit/registry", "dijit/form/NumberSpinner", "dojo/parser"], function(ready, mouse, on, registry) {
ready(function() {
on(registry.byId("mySpinner").domNode, mouse.wheel, function(evt) {
console.log(evt.detail);
});
});
});
It will show you that this value is 3 or -3 when executed in Firefox.
If you really don't want it to depend on what the browser says, you can override the _mouseWheeled function:
FixedNumberSpinner = declare("dijit/form/FixedNumberSpinner", [ NumberSpinner ], {
_mouseWheeled: function(/*Event*/ evt){
evt.stopPropagation();
evt.preventDefault();
var wheelDelta = evt.wheelDelta > 0 ? 1 : -1;
var detailDelta = evt.detail > 0 ? -1 : 1;
var scrollAmount = evt.detail ? detailDelta : wheelDelta;
if(scrollAmount !== 0){
var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];
this._arrowPressed(node, scrollAmount, this.smallDelta);
if(this._wheelTimer){
this._wheelTimer.remove();
}
this._wheelTimer = this.defer(function(){
this._arrowReleased(node);
}, 50);
}
}
});
But please remember that the implementation might still change in the near future, so personally I would just stick with the increment of 3.
A full example can be found on JSFiddle: http://jsfiddle.net/4ZQTY/5/
EDIT: As mentioned in the comments, an even easier solution would be to override the adjust() function.
In most cases it is best to leave the behavior of such widgets alone. The mouse wheel action taken will be familiar to the users of each browser as the stock input widgets respond the same way.
In the event that over-riding this does make sense, you can tweak the adjust() method of the dijit widget. If you want to force the widget to step through every intermediate value no matter size adjustment was requested, you can force the delta value to be 1, then proceed with the contents of the original function.
adjust: function (val, delta) {
delta = delta > 0 ? 1 : -1;
return this.inherited(arguments);
}
(jsfiddle)
Thanks to Dimitri M's answer for putting me onto the hunt, but I found overriding the value in adjust() to be simpler than re-defining _mouseWheeled().

Drop down input in IE8

How can I make the drop down show all the content of one option when it is expanded? If an option in the drop down is, for instance, a whole sentence and select tag width is small, the user in IE will not be able to read whole option. This is not the case in Mozilla where the whole content is shown when drop down is expanded.
Is there any way to avoid this behavior in IE8,
Thanks
I had a similar constraint when working against IE8 and the oh so famous drop down list truncating. I have multiple drop down lists on my page, one after another, some inside top nav content, and IE8 decides to cut off my attribute option text properties. Now, like many of us, I don't want to set the width obscurely large, so this option is out of question.
After a lot of research, I couldn't find a great answer, so I went ahead and fixed it with jQuery and CSS:
First, let's make sure we are only passing our function in IE8:
var isIE8 = $.browser.version.substring(0, 2) === "8.";
if (isIE8) {
//fix me code
}
Then, to allow the select to expand outside of the content area, let's wrap our drop down lists in div's with the correct structure, if not already, and then call the helper function:
var isIE8 = $.browser.version.substring(0, 2) === "8.";
if (isIE8) {
$('select').wrap('<div class="wrapper" style="position:relative; display: inline-block; float: left;"></div>').css('position', 'absolute');
//helper function for fix
ddlFix();
}
Now onto the events. Since IE8 throws an event after focusing in for whatever reason, IE will close the widget after rendering when trying to expand. The work around will be to bind to 'focusin' and 'focusout' a class that will auto expand based on the longest option text. Then, to ensure a constant min-width that doesn't shrink past the default value, we can obtain the current select list width, and set it to the drop down list min-width property on the 'onchange' binding:
function ddlFix() {
var minWidth;
$('select')
.each(function () {
minWidth = $(this).width();
$(this).css('min-width', minWidth);
})
.bind('focusin', function () {
$(this).addClass('expand');
})
.change(function () {
$(this).css('width', minWidth);
})
.bind('focusout', function () {
$(this).removeClass('expand');
});
}
Lastly, make sure to add this class in the style sheet:
select:focus, select.expand {
width: auto;
}