Find and change materialize generated html elements from react component - javascript

In a couple of places of my app, I have some code I am not very proud of. I need to find some elements that are handled by materialize to manipulate them, so that they are displayed according to my needs.
So I do this two things in two different parts of my code:
// 1.- set style from grey (placeholder text) to black(input text) and erase placeholder only on 1rst option select
const dropdownWrapper = document.getElementsByClassName('select-dropdown dropdown-trigger')[0];
dropdownWrapper.setAttribute("style", "color:black;");
// 2.- remove AM PM labels from display
let ampmLabels = document.getElementsByClassName('timepicker-span-am-pm')[0];
ampmLabels.setAttribute("style", "display:none;");
I don't consider useRef because the elements are not part of any specific component. They are in the DOM put there by materialize when I initialize the materialize element in my component and I manipulate them from that component to fit my needs when they're displayed.
As I know there are no more elements of this type when I run de code, the document.getElementsByClassName('select-dropdown dropdown-trigger')[0]; works, but isn't there a more elegant way to find a manipulate dom elements to do this?
Edit:
The componenet where the color cannot be changed is an input type with a type="text" attribute:
html with dropdownWrapper.classList.add('text-black');:
<input class="select-dropdown dropdown-trigger text-black" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804">
html with dropdownWrapper.setAttribute("style", "color:black;");:
<input class="select-dropdown dropdown-trigger" type="text" readonly="true" data-target="select-options-ee9a6017-aef6-ecbf-c2a1-298693b77804" style="color: black;">
Seems that because of that the dropdownWrapper.classList.add('text-black'); does not work. This adds the text black to the class name in the class="select-dropdown dropdown-trigger text-black" (note the text-black at the end) but does not change the text color even if the .text-black {color: black} is added to the css file.
The style change with setAttribute, produces the style="color: black;" at the end of the html that is what seems what is actually changing the color.

You can do something like this:
function addClass(selector, className) {
const element = document.querySelector(selector);
element.classList.add(className);
}
/* maybe move these strings to constants, add comments*/
addClass('.select-dropdown.dropdown-trigger', 'text-black');
addClass('.timepicker-span-am-pm', 'hidden');
Tiny improvements:
You can use document.querySelector()
You can also add the styles in a CSS class and use classList API:
Long version:
const dropdownWrapper = document.querySelector('.select-dropdown.dropdown-trigger');
dropdownWrapper.classList.add('text-black');
const ampmLabels = document.querySelector('.timepicker-span-am-pm');
ampmLabels.classList.add('hidden');

Related

Tailwind custom pseudo element

I'm trying to create a single js file for a component that is used with several styles in my project.
On one page I have several buttons for some features, with a default background color set in the html file (for exemple bg-gray-500).
For buttons where the feature is activated I change the background color, currently with js, but therefore the bg color for the "activated feature" (for exemple bg-blue-500) is defined in the js and this is what I would like to move to the html file.
So, instead of having <button type="button" class="bg-gray-500"></button> and having the js removing the class bg-gray-500 and adding the class bg-blue-500, I wonder if this is possible to have something like <button type="button" class="bg-gray-500 selected:bg-blue-500"></button> where the js would only have to add or remove the class selected to switch between the one and the other color, instead specifing the color itself.
Thank you
You may write simple plugin for custom variants
// tailwing.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
theme: {
extend: {},
},
plugins: [
plugin(function({ addVariant }) {
addVariant('selected', '&.selected');
addVariant('parent-selected', '.selected &');
})
],
}
HTML
<div>
<button class="bg-blue-500 selected:bg-red-500 selected">
Button
</button>
</div>
<div class="selected">
<button class="bg-blue-500 parent-selected:bg-yellow-500">
Button
</button>
</div>
The magic here is addVariant() function where the first parameter is variant name (could be any but must be unique among all variants - in HTML use it like selected:), second - CSS selector (so &.selected means element with class .selected) or callback function which should return string as CSS selector
In a demo I created two cases just for example - toggle class on element itself or parent element
DEMO - toggle selected class to see effect

Color Picker design and value inheriting to another div

I am using this color picker http://acko.net/blog/farbtastic-jquery-color-picker-plug-in/
Its by steven
Though from the docs i am using it as
$(document).ready(function() {
$('#picker').farbtastic('#color');
});
And html code is `
`
I have to create it into two separate division. I want color hex value to be changed in input but shows the colour in another division background.
If i use it like this
<div id="colorpicker"></div>
<input type="text" id="color" name="color" value="#123456" />
<div id='color' ></div>
The update will take place in one id so in this only input will change with color and its hex value.
From the script http://acko.net/files/farbtastic/demo/farbtastic.js
it takes only one parameter in function so i want this way, that when ever color of division change the color hex value should update under input.
You still can't use two elements with the same ID. It doesn't work that way. From the script authors web page, passing in the destination ID gives you exactly what the demo does. If you scroll further down, there are instructions where you can pass in a function. This is what you want to do:
$('#colorpicker').farbtastic(setColors);
var setColors = function(color){
$('#colorText').val(color);
$('#colorBackground').css('background-color' : color);
}
I haven't tested this, but you should get the point and be on the right road.
[UPDATE]
I tested this in a fiddle, and it doesn't work, though it is exact per the authors documentation. So what you can do is:
<div id="colorpicker"></div>
<input type="text" id="colorText" value="#123456" />
<div id="colorDiv">div<div>
Two seperate ID's, one for the div, one for the text, and just select them both:
var domNodes = $('#colorDiv, #colorText');
$('#colorpicker').farbtastic(domNodes);
Here is the Fiddle
Also, if you don't want the input to have the background color at all, you can override the default functionality and do whatever you want like:
JSFiddle
$.farbtastic(colorpicker).linkTo(callBack);
function callBack(color) {
$('#colorText').val(color);
$('#colorDiv').css('background-color', color);
}

Wrapping a jquery validate span.error with nested divs

Heyo. This is my first stack overflow post because I am stumped and not finding many people who are trying to accomplish the same thing. I've tried using jquery .before(), .after(), and .wrap() to resolve this. I was initially using css :before and :after pseudo-elements, but as that won't work for legacy browsers, I've decided to use jquery.
I already have several forms on several pages with validation working. The error messages vary in length. We were using a static, one size background image on the default span element, so content was bleeding out on longer error messages. I built a flexible rounded corner series of nested divs to allow the error box to grow or shrink dynamically. The html I want to output is:
<div class="errorWrap">
<div class="errorTop"><span></span></div>
<div class="errorContent">
<span class="error">This is an error</span>
</div>
<div class="errorBottom"><span></span></div>
</div>
Here's an example of a solution I tried, but I'm still pretty new to javascript.
$('.error').before('<div class="errorWrap"><div class="errorTop"><span></span></div><div class="errorContent">');
$('.error').after('</div><div class="errorBottom"><span></span></div></div>');
Correct me if I'm wrong, but I think that I have the right idea with the jquery. But it's just kind of sitting there, not in any function being called. So I imagine that since the code isn't re-executing, it just doesn't show up. Is there an appropriate function to wrap this in? I'm certain I'm just not attacking this from the right direction. Any help is super appreciated.
the plugins "before" and "after" dont take html as string. you cannot start a div in one and close it in an other.
Either you take your current html and generate a new html string which you append where you want to or you use the "wrap" plugin http://api.jquery.com/wrap/
Using pure HTML
$(".error").html("<div class='beforeContent'>" + $(".error").html() + "</div>");
Using wrap (http://api.jquery.com/wrap/)
$(".error").wrap("<div class='beforeAndAfter'></div>");
If you want to show an error div after focus out of an input then you have to create it using html/wrap as Luke said and then you have to append it in ot the dom useing
$('.errorWrap').insertAfter('.focusedElement');
But there are other methods available to insert a new element like append/appendTo e.t.c,
I ended up fixing this problem on my own using jquery to create the div and it's nesting on pageload, the divs are generated with an error class that gives display:none. A custom errorPlacement function nests the error in the correct div. Then I used a custom validator highlight function to remove the class that hides the element. Then I used the unhighlight function to re-add the class to re-hide the div.
$(function() {
//Generate the elements and assign attributes
var errorWrap = document.createElement('div');
$(errorWrap).addClass('errorWrap hideError');
var errorTop = document.createElement('div');
$(errorTop).addClass('errorTop');
var topSpan = document.createElement('span');
var errorContent = document.createElement('div');
$(errorContent).addClass('errorContent');
var errorBottom = document.createElement('div');
$(errorBottom).addClass('errorBottom');
var bottomSpan = document.createElement('span');
//Place the elements directly after each dd element
$("dl > dd").append(errorWrap);
$("div.errorWrap").append(errorTop)
.append(errorContent)
.append(errorBottom);
$("div.errorTop").append(topSpan);
$("div.errorBottom").append(bottomSpan);
//Add custom validator defaults
$.validator.setDefaults({
errorPlacement: function(error, element) {
$(element).nextAll('.errorWrap').children('.errorContent').append(error);
},
highlight: function(element) {
$(element).nextAll('.errorWrap').removeClass('hideError');
},
unhighlight: function(element) {
$(element).nextAll('.errorWrap').addClass('hideError');
}
});
}
Although I'm sure this could have been done more shorthand, I really like this technique because I didn't have to update any of my pages that contained forms to get it to work. All of the nested divs are dynamically created by javascript, so I can include a global file to any page with forms and it will just work. Thanks for all who offered suggestions.

What does style.display = '' actually do?

After researching this issue for a couple of hours, I found that one of the most efficient ways to toggle a page element's display (in HTML) is to do something like:
// showing
document.getElementById('element').style.display = '';
// hiding
document.getElementById('element').style.display = 'none';
Simple question: What does style.display = '' actually do?
Does it "reset" the original display property?
Or does it remove the display property, thereby using the default style for display?
..........................................
Would be nice to know: Does anyone know of any links to any kind of documentation about this?
(Yes, I have Google-d this issue, but I'm probably not entering the right search term and keep coming up with completely un-related search results.)
Thanks for any suggestions or links.
Yes, it resets the element's display property to the default by blanking out the inline "display: none", causing the element to fall back on its display property as defined by the page's ranking CSS rules.
For example, here's a <div> with the ID of "myElement".
<div id="myElement"></div>
A <div> has a setting of display:block by default. In our style sheet, suppose we specify that your <div> is to be displayed as table:
div#myElement
{
display:table;
}
Upon loading your page, the <div> is displayed as table. If you want to hide this <div> with scripting, you might do any of these:
// JavaScript:
document.getElementById("myElement").style.display = 'none';
// jQuery:
$("#myElement").toggle(); // if currently visible
$("#myElement").hide();
$("#myElement").css({"display":"none"});
All of thse have the same effect: adding an inline style property to your <div>:
<div id="myElement" style="display:none"></div>
If you wish to show the element again, any of these would work:
// JavaScript:
document.getElementById("myElement").style.display = "";
// jQuery:
$("#myElement").toggle(); // if currently hidden
$("#myElement").show();
$("#myElement").css({"display":""});
These remove the display CSS property from the inline style property:
<div style=""></div>
Since the inline style no longer specifies a display, the <div> goes back to being displayed as table, since that's what we put in the style sheet. The <div> does not revert to being displayed as block because our CSS overrode that default setting; blanking out the inline display property does not negate the rules in our style sheets.
For giggles, here's the Google query I used for verification of my answer: javascript style display empty string default
...and a couple of links where this is mentioned:
http://jszen.blogspot.com/2004/07/table-rowsrevealed.html
http://www.harrymaugans.com/2007/03/05/how-to-create-a-collapsible-div-with-javascript-and-css/
(not in the article, but in the comments section)
It sets the display style to the default value for that element. For most elements if not all, the default value is something other than none.
It removes the value for the display property so that the default value is used.
It does not reset the original display property.
If you for example have this:
<span id="test" style="display:block;">b</span>
And do this:
document.getElementById('test').style.display = 'inline';
document.getElementById('test').style.display = '';
the display style used for the element ends up being inline because that's the default for the element, it is not reset back to the style specified in the HTML code.
It sets the css for that element's display to null which essentially wipes out what was set and it reverts to its default value.

Javascript: Dynamic Generation of a Div

I have several vertically stacks divs and I want to have a div appear when I click a button within each of these divs. The div that I want to appear will be the exact same for each appearance with the exception of an id associating it with the outer div. How do I do this in Javascript?
I assume I should use the createElement() within Javascript, but how do I append it to the end of a specific element. Also, when creating an element, I have to hardcode the html in the Javascript file. Is there anyway to leave the element within the html design file. I want to seperate design from code as much as possible.
Clone Node
var clone = myDiv.cloneNode();
Example (live demo):
HTML
<div>
<input type="button" onclick="functionClone(this);" value="Dolly"/>
<input type="button" onclick="functionClone(this);" value="Dolly_1"/>
</div>
Javascript:
functionClone = function(subject){
var clonenode = subject.cloneNode(true);
subject.value = subject.value + '\'s been cloned!';
subject.disabled = true;
insertElementAfter(subject, clonenode);
}
insertElementAfter = function(subject, newElement){
subject.parentNode.insertBefore(newElement,subject.nextSibling);
}
To append an element below your div use this:
subject.parentNode.appendChild(clonenode)

Categories

Resources