index of matching items in parent element even if they're in other child containers - indexing

I need to get the index of the li.play relevant to the ul.showreel_thumbnails. Is this even possible? All i seem to get is the li index inside ul.row
<ul class="showreel_thumbnails">
<li>
<ul class="row">
<li class="play_video">item</li>
<li class="play_video">item</li>
<li class="play_video">item</li>
</ul>
</li>
<li>
<ul class="row">
<li class="play_video">item 4</li>
<li class="play_video">item</li>
</ul>
</li>
</ul>
so if item 4 is clicked it should give me the index of 4 etc...
best, Dan.

It may not be valid HTML but here's how it would work (with JQuery):
function FindMyCount()
{
var item_count = 0;
$("#showreel_thumbnails li").each(function() {
++item_count;
if($(this).hasClass("igotclicked"))
return false;
});
return item_count;
}
$("#showreel_thumbnails li").click(function() {
$(this).addClass("igotclicked");
var myCount = FindMyCount(); // 1 - the # of li's under the showreel piece
$(this).removeClass("igotclicked");
// Do what you want here.
});

Related

iterating number type in express-edge?

isn't it possible to itereate through a number type variable in express-edge? On their official docs they mentioned iteration of objects and arrays and when I tried to iterate a number type variable it didn't worked (i mean like a simple loop, will run for n times)
so basically i'm trying to impelment a pagination, my controller for this look something like this:
// get total documents in the Posts collection
const count = await Posts.countDocuments();
const tpgs = Math.ceil(count / limit);
// return response with posts, total pages, and current page
res.render("index",{
psts: posts,
totalPages: tpgs,
currentPage: page
});
and the html (with express-edge) looks something like this:
#if(totalPages > 0)
<nav aria-label="Page navigation example">
<ul class="pagination">
#each(p in totalPages)
#if(p == 1)
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
#else
<li class="page-item"><a class="page-link" href="posts/{{ p - 1}}">Previous</a></li>
#endif
#if(p == currentPage)
<li class="page-item active" aria-current="page">
<a class="page-link" href="{{ p }}">{{ p }}</a>
</li>
#else
<li class="page-item"><a class="page-link" href="posts/{{ p }}">{{ p }}</a></li>
#endif
#if(p == totalPages)
<li class="page-item disabled">
<a class="page-link" href="posts/{{ p + 1}}">Next</a>
</li>
#else
<li class="page-item">
<a class="page-link" href="posts/{{ p + 1}}">Next</a>
</li>
#endif
#endeach
</ul>
</nav>
#endif

Display nested loop in Vue from a GraphQL query

I'm using OneGraph to pull data from Spotify. I can't figure how to render out the 3rd nested loop though even looking at other Vue code samples. I'm trying to return the artist name for each playlist as shown below.
<template>
<ul>
<li v-for="(item, index) in $page.oneGraph.spotify.me.playlists" :key="index">
<ol>
<li v-for="track in item.tracks" :key="track.playlists">
{{track.name}} -
<span v-for="artist in item.tracks.artists" :key="artist.tracks">
{{artist.name}}
</span>
</li>
</ol>
</li>
</ul>
</template>
The query:
{
spotify {
me {
id
playlists(limit: 1) {
name
tracks {
name
artists {
name
}
}
}
}
}
}
Nested loop:
<li v-for="track in item.tracks" :key="track.playlists">{{track.name}}</li>
Child nested loop:
<span v-for="artist in track.artists" :key="artist.tracks" {{artist.name}}</span>

Space disabled on concatenation

I have an array which looks like this
skills: [
"HTML5",
"CSS3",
"SCSS",
"Bootstrap",
"JavaScript",
"Vue.js",
"PHP",
"MySQL",
"Symfony"
]
And in my template I'm doing something like
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ', '}}</li>
</ul>
But what I get is
HTML5,CSS3,SCSS,Bootstrap,JavaScript,Vue.js,PHP,MySQL,Symfony,
How do I able the spaces?
Btw is there a better way to concatenate the elements of my array? I first used join() like that
<ul>
<li v-for="(skill,index) of skills.join(', ')" :key="index">{{ skill }}</li>
</ul>
But not only the spaces are still disabled but it returns every character of my elements, I don't know why
Like
<ul data-v-c226fde6="">
<li data-v-c226fde6="">H</li>
<li data-v-c226fde6="">T</li>
<li data-v-c226fde6="">M</li>
<li data-v-c226fde6="">L</li>
<li data-v-c226fde6="">5</li>
<li data-v-c226fde6="">,</li>
<li data-v-c226fde6=""> </li>
<li data-v-c226fde6="">C</li>
<li data-v-c226fde6="">S</li>
<li data-v-c226fde6="">S</li>
<li data-v-c226fde6="">3</li>
...
EDIT: otherwise what I could just do is
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ','}}</li>
</ul>
And then adding some padding-right to the li but I don't know if it's good practice + I don't know how I would remove the comma after the last element
Inside html template such as li you have to specify space characters using ;
<ul>
<li v-for="(skill,index) of skills" :key="index">{{ skill + ','}} </li>
</ul>
also checkout https://www.w3schools.com/html/html_entities.asp
to learn more about HTML entities
With that code you will get a list of <li></li> elements with each skill looking like this:
<li>HTML5,</li><li>CSS3,</li><li>...
just add a class or even a style with a margin to the right to add a little space between the elements either:
<ul>
<li v-for="(skill,index) of skills" style="margin-right: 5px" :key="index">{{ skill }}</li>
</ul>
better:
<ul>
<li v-for="(skill,index) of skills" class="class-with-some-margin-right" :key="index">{{ skill }}</li>
</ul>
You can add the ', ' after each item using CSS like so:
var example1 = new Vue({
el: '#example-1',
data: {
skills: ["HTML5", "CSS3", "SCSS", "Bootstrap", "JavaScript",
"Vue.js", "PHP", "MySQL", "Symfony", ]
}
})
/* styling help:
Q: https://stackoverflow.com/questions/1517220/
A: https://stackoverflow.com/a/1517228/7505395 */
#example-1 {
display: inline;
list-style: none;
}
#example-1 li {
display: inline;
}
#example-1 li:after {
content: ", ";
}
#example-1 li:last-child:after {
content: "";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<ul id="example-1">
<li v-for="(sk, idx) in skills" :key="idx">{{ sk }}</li>
</ul>
This answer incorporates it into Vue, for the pure css answer, go here.
As always you can also combine normal text inside Vues {{}} like so : {{ skill + ', ' }} - not sure if thats helpfull though as it applies to all replacement and you end up having a trailing ,

How to keep the tab active? ASP.NET Core Razor Pages

Hi there,
I have a problem with my tabs in navbar.
The result I wish:
See the "Home" tab class active by default
Clicking on another tab must to remove active class from the <a> that is already active (at the starting point it is "Home" tab)
Add the same class active to the tab I click on (which also mean that app redirects me)
Keep the clicked tab active
What I've got so far:
I see the "Home" tab set active by default
Clicking on any tab removes class active as I mentioned above and adds the same class to the clicked tab
Redirection happens and "Home" tab returns its default state (becomes active again)
I share my code below:
HTML
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" id="navigation">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link active" id="home" asp-area="" asp-page="/home/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" id="declarations" asp-area="" asp-page="/declarations/Index">Declarations</a>
</li>
<li class="nav-item">
<a class="nav-link" id="topics" asp-area="" asp-page="/topics/Index">List of Topics</a>
</li>
<li class="nav-item">
<a class="nav-link" id="contacts" asp-area="" asp-page="/contacts/Index">Contacts</a>
</li>
<li class="nav-item">
<a class="nav-link" id="faq" asp-area="" asp-page="/faq/Index">FAQ</a>
</li>
</ul>
</div>
jQuery
$("#navigation .navbar-nav a").click(function() {
$("#navigation .navbar-nav").find("a.active").removeClass("active");
$(this).addClass("active");
localStorage.className = "active";
});
$(document).ready(function() {
stayActive();
});
function stayActive() {
$(this).children().addClass(localStorage.className);
}
Since you are using Razor page, everytime user clicks on a tab, the page will be rendered again on server and then sent back. Therefore I suggest that we set the active class on serverside based on the current route.
Add a new HtmlHelper class
public static class HtmlHelperExtensions
{
public static string ActiveClass(this IHtmlHelper htmlHelper, string route)
{
var routeData = htmlHelper.ViewContext.RouteData;
var pageRoute = routeData.Values["page"].ToString();
return route == pageRoute ? "active" : "";
}
}
Go to your _ViewImports.cshtml and add this import.
Without this, it will not recognize the helper we're about to add in step 3.
#using <Namespace of the class you wrote in step 1, if not already here>
Then your cshtml will be
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse" id="navigation">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link #Html.ActiveClass("/home/Index")" id="home" asp-area="" asp-page="/home/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link #Html.ActiveClass("/declarations/Index")" id="declarations" asp-area="" asp-page="/declarations/Index">Declarations</a>
</li>
...Same for 3 other tabs, make sure that the route you pass in ActiveClass method
...must be the same as the route in asp-page
...If you're afraid of duplication, make some static class to store these routes as constants
</ul>
</div>
In addition to #Nam Le answer I suggest complete solution.
I've found the way how can we use the exception properly.
First of all, as we set active class on serverside based on the current route, we have to add asp-route-routeId="{routeId:int}" in the cshtml we work with.
Secondly, use this jQuery code:
jQuery
$("#navigation .navbar-nav a").click(function() {
$("#navigation .navbar-nav").find("a.active").removeClass("active");
$(this).addClass("active");
localStorage.className = "active";
});
$(document).ready(function() {
stayActive();
});
function stayActive() {
$(this).addClass(localStorage.className);
}
And the last step is to setup "launchUrl": "route/routeId" in the launchSetting.json file to run the application with certain route. This action make our HtmlHelper extension react and add active status to the tab we want.
Hope that here is no any gross mistakes in the solution I suggest :)
UPD: don't forget to add route in cshtml #page "/route/routeId"

Getting nested <li> tags also.....just need the direct <li> item

I have a page structure where it includes hyperlinks with different levels of nested list items. I am writing the xpath for just the second nested list items(level 2) but it is also giving me all the list items below level 2(level 3 or below), which i don't need. It's getting really frustrating now because I have tried different xpaths and cssSelectors, everytime it is taking the level 3 list items along with level 2.
The page structure is exactly like following:
<div>
<ul class="menuBar_menu_lvl_0">
<li class="item_lvl_1">
<li class="item_lvl_1">
<ul class="menu_lvl_1">
<li class="item_lvl_2"></li>
<li class="item_lvl_2"></li>
<li class="item_lvl_2">
<ul class="menu_lvl_2">
<li class="item_lvl_3"></li>
<li class="item_lvl_3"></li>
<li class="item_lvl_3"></li>
</ul>
</li>
</ul>
<li class="item_lvl_1">
<li class="item_lvl_1">
xpath = //ul[#class="menuBar_menu_lvl_0"]//li[#class="item_lvl_1"]//ul[#class="menu_lvl_1"]//li[#class="item_lvl_2"]
This is also giving me item number 3 elements along with item level 2. I want to get each level item correctly and separately. Anybody's help would be highly appreciated
Welcome to SO.
Here is the sample that used.
<html>
<body>
<div>
<ul class="menuBar_menu_lvl_0">
<li class="item_lvl_1">
<li class="item_lvl_1">
<ul class="menu_lvl_1">
<li class="item_lvl_2">Level1-li1</li>
<li class="item_lvl_2">Level1-li2</li>
<li class="item_lvl_2">
<ul class="menu_lvl_2">
<li class="item_lvl_3">Level2-li1</li>
<li class="item_lvl_3">Level2-li2</li>
<li class="item_lvl_3">Level2-li1</li>
</ul>
Level1-li3
</li>
</ul>
<li class="item_lvl_1">
<li class="item_lvl_1">
</ul>
</div>
</body>
</html>
And below is the xpath
//ul[#class='menu_lvl_1']//li[not(parent::ul[#class='menu_lvl_2'])]
Here is the output:
Here is the method to get the text from parent element only.
def get_text_exclude_children(element):
return driver.execute_script(
"""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element).strip()