I have a component to show a sort of Table of Contents. I'm struggling with react for it is creating a span tag where, in my understanding, it shouldn't.
The rendering functions is:
render() {
return(
<ul>
{
this.state.contents.map(function(li, i) {
let subItems = li.subItems.map(function(subLi, j) {
return (
<li>
<span>{subLi.title}</span>
</li>
)
}, this);
return (
<li tabIndex={i}>
<span><i class="fa fa-caret-right" />{li.title}</span>
<ul class="subitens">
{subItems}
</ul>
</li>
);
}, this)
}
</ul>
);
The line <span><i class="fa fa-caret-right" />{li.title}</span> is creating the following structure:
<span>
<i></i>
<span>Parent 1</span>
</span>
And I would like:
<span><i></i> Parent 1</span>
That span around my text is messing with my CSS.
I wrapped it up on a fiddle: https://jsfiddle.net/fpcvzsLo/
Any ideas on what am I getting wrong?
Thanks!
As #degr told, this is a known issue with old react versions. It emits tags along with every text.
All I did was to update my React to 0.15 and it works.
Thanks!
Try the following:
return (
<li tabIndex={i}>
<span className="fa fa-caret-right">
{li.title}
</span>
<ul className="subitens">
{subItems}
</ul>
</li>
);
https://jsfiddle.net/fpcvzsLo/4/ (included Font Awesome to show)
Output:
<span class="fa fa-caret-right" data-reactid=".0.1.0">Parent 2</span>
Related
I a working on a to make a reponsive dropdown navigation bar with vanilla JavaScript. In mobile view I want that upon click one dropdown the another should close. JavaScript here:
dropbtns.forEach(link => {
link.addEventListener("click", function(e) {
e.currentTarget.nextElementSibling.classList.toggle("showdd");
});
});
and show dropdown:
.showdd {
height: auto;
}
html code:
<div class="nav-container">
<div class="brand">
Logo
</div>
<nav>
<div class="nav-mobile"><a id="nav-toggle" href="#!"><span></span></a></div>
<ul id="nav-list">
<li>
Home
</li>
<li>
About
</li>
<li class="dropdown">
</i>
<ul class="nav-dropdown">
<li>
Web Design
</li>
<li>
Web Development
</li>
<li>
Graphic Design
</li>
</ul>
</li>
<li>
Pricing
</li>
<li class="dropdown">
</i>
<ul class="nav-dropdown">
<li>
Web Design
</li>
<li>
Web Development
</li>
<li>
Graphic Design
</li>
</ul>
</li>
<li>
Contact
</li>
</ul>
</nav>
</div>
full code can be find here.
So, if you want to collapse all other .nav-dropdown when one is being clicked on, you simply will need to:
Store the reference of the .nav-dropdown of the current element (for comparison later)
Toggle its class (as you're doing already)
Go through all other .nav-dropdown in your DOM tree and iterate through them. If they do not match the current reference, then you know the dropdown belongs to another link and you can remove the class
With that in mind we arrive at the code below:
dropbtns.forEach(link => {
link.addEventListener('click', e => {
const ownDropdown = e.currentTarget.nextElementSibling;
ownDropdown.classList.toggle('showdd');
document.querySelectorAll('.dropbtn + .nav-dropdown').forEach(el => {
if (el !== ownDropdown)
el.classList.remove('showdd');
});
});
});
It works on your Codepen after I edit the following line.
links.forEach(link => {
link.addEventListener("click", function(e) {
links.forEach(link => {
link.nextElementSibling.classList.remove("showdd"); // Here
});
e.currentTarget.nextElementSibling.classList.toggle("show");
});
});
By the way, what is "showdd"?
How can I access the following element, with watir. I always get error.
<div style="visibility: visible;"><div id="nav">
<div id="nav-toggle"></div>
<ul id="itens-menu">
<li>
<a href="#cartao-01">
<i class="icon-table"></i>ponto 01</a>
</li>
<li class="ativo">
<a href="#batidas-02">
<i class="icon-clock"></i>Inclusão de Ponto</a>
</li>
<li>
<a href="#calculadora-03">
<i class="icon-calculator"></i>Calculator</a>
</li>
</ul>
</div>
</div>
I'm trying something like:
site = Watir::Browser.start(SITE1, :chrome)
site.ul(:id => "itens-menu").li(:class => "ativo").i(:class => "icon-clock").click
How can I click this element?
<i class = "icon-clock"> </ i> I
in the above example structure
Have you tried waiting for the element present before interacting?
site.element(class: "icon-clock").wait_until(timeout = 30, &:present?).click
Alternatively you can use fireevent to click
site.element(class: "icon-clock").wait_until(timeout = 30, &:present?).fire_event :click
'timeout' is optional, wait_until will wait for watir default timeout which is 5 secs.
Here I am waiting for 30 sec in my above sample code.
******** EDITED TO SIMPLIFY EXAMPLE AND CLARIFY REQUIREMENT AND PROBLEM **********
I'm stumped with this one, I hope someone can help.
I have a nav bar that I need to run a function on to add .active classes to li elements if they have descendants of a.active.
The menu system is a React component: -
import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'
import {activateMenu} from './ActivateMenu'
class SidebarMenu extends React.Component {
componentDidMount() {
activateMenu()
}
componentDidUpdate() {
activateMenu()
}
render() {
const renderNavLink = (to, text, icon, renderArrow = false) => {
return(
<NavLink to={to}>
<i className="bullet">{icon}</i>
<span>{text}</span>
{renderArrow ? <span className="pull-right-container">
<i className="angle-left"><FaAngleLeft /></i>
</span> : null}
</NavLink>
)
}
return (
<ul className="sidebar-menu" data-widget="tree">
<li className="">
{renderNavLink('/','Home',<FaHome />)}
</li>
<li className="treeview">
{renderNavLink("#",'Users',<FaGroup />, true)}
<ul className="treeview-menu">
<li>
{renderNavLink(userSearchSlug,'Search',<FaSearch />)}
</li>
</ul>
</li>
<button onClick={activateMenu}>Press Me</button>
</ul>
)
}
}
export default SidebarMenu
This will give me an HTML structure like this: -
<ul class="sidebar-menu tree" data-widget="tree">
<li class="treeview">
<a href="#">
<i class="fa fa-dashboard"></i> <span>Links</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li>
<i class="fa fa-circle-o"></i> Link1
</li>
<li>
<i class="fa fa-circle-o"></i> Link2
</li>
</ul>
</li>
</ul>
After React has rendered the HTML, I need to trigger a click event on the the .treeview > a node if any a.active nodes are found under .treeview-menu. So: -
<li class="treeview">
<a href="#" *****TRIGGER CLICK EVENT*****>
<i class="fa fa-dashboard"></i> <span>Links</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li>
<i class="fa fa-circle-o *****.ACTIVE CLASS HERE****"></i> Link1
</li>
<li>
<i class="fa fa-circle-o"></i> Link2
</li>
</ul>
</li>
activeMenu() looks like this: -
$('ul.sidebar-menu li.treeview:not(.menu-open)').has('a.active').find('a').trigger( "click" );
This function works when called from onClick() from a button on the page but it is not working in componentDidMount() and componentDidUpdate(). The function will run (tested with console.log() but not affect the HTML as it should. However, if I run it from a Button, it works perfectly. It also works perfectly when HMR runs.
I've no idea why this is happening. Does anyone have any ideas?
This is probably happening because you're selecting the element directly rather than using refs, although it's hard to say because we have no idea what $('ul.sidebar-menu .treeview a').parent().has('a.active').parent().find('.treeview a') is selecting, which is why this kind of code is an antipattern.
React may be in some state where it's not prepared to handle click events at those points. Try using something like the following:
import React, {Component} from "react";
import { Link, NavLink } from 'react-router-dom'
class SidebarMenu extends React.Component {
constructor(props) {
super(props);
this.menuRefs = [];
}
componentDidUpdate() {
if (this.menuRefs.length) {
this.menuRefs[0].click();
}
}
render() {
const renderNavLink = (to, text, icon, renderArrow = false) => {
return(
<NavLink to={to} innerRef={ref => this.menuRefs.push(ref)}>
<i className="bullet">{icon}</i>
<span>{text}</span>
{renderArrow ? <span className="pull-right-container">
<i className="angle-left"><FaAngleLeft /></i>
</span> : null}
</NavLink>
)
}
return (
<ul className="sidebar-menu" data-widget="tree">
<li className="">
{renderNavLink('/','Home',<FaHome />)}
</li>
<li className="treeview">
{renderNavLink("#",'Users',<FaGroup />, true)}
<ul className="treeview-menu">
<li>
{renderNavLink(userSearchSlug,'Search',<FaSearch />)}
</li>
</ul>
</li>
<button onClick={() => this.menuRefs[0] && this.menuRefs[0].click()}>Press Me</button>
</ul>
)
}
}
export default SidebarMenu
Notice
Now there's an array of "menuRefs" and you just use them like normal DOM elements.
We push to the menuRefs in the NavLink innerRef prop (found here)
Note however that you may want to keep a map to ensure that no duplicates get pushed into menuRefs.
To learn more about refs, visit the docs: https://reactjs.org/docs/refs-and-the-dom.html
I am restyling a list of related articles in a li and I would like to remove the "-" between the a tag and span without messing with the original content on the page (links). I must use jQuery and I'm not sure if there is a simple way of doing this.
<div class="related-articles card">
<h3 class="h2">
<i class="fa fa-book text-brand-primary-dark"></i> Related Articles
</h3>
<ul>
<li>
Title One
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three
-
<span> Some RelatedPreview Text... </span>
</li>
</ul>
Here is my solution, get the children elements and assign it back, so the plain text present (-) will get removed!
$('.related-articles li').each(function() {
$(this).html($(this).children());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="related-articles card">
<h3 class="h2">
<i class="fa fa-book text-brand-primary-dark"></i> Related Articles
</h3>
<ul>
<li>
Title One -
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two -
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three -
<span> Some RelatedPreview Text... </span>
</li>
</ul>
One way would be to loop through each <li>, extract the <a> and <span> elements and stitch them together manually, like this:
$("ul > li").each( (i, li) => {
const $li = $(li);
const $a = $li.find("a");
const $span = $li.find("span");
//create a temp element with just the <a> and <span>
const $tempItem = $("<li></li>");
$tempItem.append( $a ).append( $span );
//copy new HTML into old element
$li.html( $tempItem.html () );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
Title One
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three
-
<span> Some RelatedPreview Text... </span>
</li>
</ul>
One option is:
$('.related-articles li a').map(function() {
return this.nextSibling;
}).remove();
I am using JQuery nested sortable to display a tree of items and I would like to disable first TWO levels from changes.
Here is jsfiddle: http://jsfiddle.net/YgF4k/18/
HTML:
<ul id='menusList'>
<li class='sortable_false'>
<div> <span class='menu_name'>
root1
</span>
</div>
<ol class='sortable'>
<li class="sortable_false" id="menu_161">
<div> <span class='menu_name'>
Child 1
</span>
</div>
</li>
<li class="sortable_false" id="menu_163">
<div> <span class='menu_name'>
Child 2
</span>
</div>
<ol>
<li class="sortable_true" id="menu_162">
<div> <span class='menu_name'>
Grandchild 1
</span>
</div>
</li>
<li class="sortable_true" id="menu_158">
<div> <span class='menu_name'>
Grandchild 2
</span>
</div>
</li>
<li class="sortable_true" id="menu_160">
<div> <span class='menu_name'>
Grandchild 3
</span>
</div>
</li>
</ol>
</li>
<li class="sortable_false" id="menu_159">
<div> <span class='menu_name'>
Child 3
</span>
</div>
</li>
</ol>
<li class="sortable_false" id="menu_2">
<div> <span class='menu_name'>
root2
</span>
</div>
</li>
</li>
</ul>
JQuery:
$('.sortable').nestedSortable({
handle: 'div',
items: 'li',
toleranceElement: '> div',
protectRoot: true,
update: function (event, ui) {
$.post("/sort", $(this).nestedSortable('serialize'));
}
});
In more details what I am still missing is:
Moving Grandchildren into Children level and vice verse should not be allowed.
Reordering of Children should not be allowed.
Moving Grandchildren between root1 Children and root2 Children should be allowed (ideally).
I've played some time with protectRoot and items options of nestedSortable, but without success.
you just need to set the items as li.sortable_true...
$('.sortable').nestedSortable({
handle: 'div',
items: 'li.sortable_true',
toleranceElement: '> div',
protectRoot: true,
update: function (event, ui) {
$.post("/sort", $(this).nestedSortable('serialize'));
}
});
See updated fiddle: http://jsfiddle.net/f9LyM/1/
also check out the jQuery UI docs, this extension inherits it: http://api.jqueryui.com/sortable/#option-items
Using newest version of jQuery.ui.nestedSortable (which currently is 2.0) solves problems with protectRoot.