Hi I'm fairly new to web development and am stuck at the very first project I have set myself.
I'm trying to create a team selection page where different team formations can be selected and the images will be dynamically ordered according to the selected formation.
I don't know if this can be achieved using CSS only, or whether I have to combine it with javascript or jquery (I'm trying to learn all 3 so it's a steep learning curve).
I think I can create a list in the html ul li, and then dynamically change the class of each li depending on the selected formation.
e.g. for soccer, formation 442 would have:
GK
DEF DEF DEF DEF
MID MID MID MID
STR STR
but if the formation was changed to 541 then the images would change to show
GK
DEF DEF DEF DEF DEF
MID MID MID MID
STR
Could anybody provide me with hints as to what possible solutions there are to this issue and I will read up further to try and understand.
e.g. do I need to create a javascript function for each formation type, give an id to each li element and set the CSS for each element depending on the selected formation
e.g do I use jquery to add CSS class to each li element depending on selected formation
Here's a piece of code which may help you with what you need.
<div>
<ul id="ulGoalkeepers"><li>GK</li></ul>
<hr />
<ul id="ulDefenders"></ul>
<hr />
<ul id="ulMidfielders"></ul>
<hr />
<ul id="ulStrikers"></ul>
</div>
<select id="ddlFormation">
<option></option>
<option value="4-4-2">4-4-2</option>
<option value="4-5-1">4-5-1</option>
</select>
<script type="text/javascript" language="javascript">
function formationChanged(){
var formation = $("#ddlFormation").val();
if (formation != undefined && formation != '') {
$("#ulDefenders").empty();
$("#ulMidfielders").empty();
$("#ulStrikers").empty();
var parts = formation.split('-');
var defenders = parts[0];
var midfielders = parts[1];
var strikers = parts[2];
for (var i = 0; i < defenders; i++) {
$("#ulDefenders").append('<li>DEF</li>');
}
for (var i = 0; i < midfielders; i++) {
$("#ulMidfielders").append('<li>MID</li>');
}
for (var i = 0; i < strikers; i++) {
$("#ulStrikers").append('<li>STR</li>');
}
}
}
$(document).ready(function () {
$("#ddlFormation").bind("change", formationChanged);
});
</script>
EDIT:
I don't like the idea with CSS because you lose the structure of html elements. Defenders, midfielders are all will be in the same list and that is not very good.
On the other hand there might be some ideas how to implement that and a lot depends on what you really need. For example:
CSS:
.team div
{
float: left;
width: 50px;
}
.team div.first
{
clear: both;
}
HTML:
<div class="team">
<div class="goalkeeper">GK</div>
<div class="defender first">DEF</div>
<div class="defender">DEF</div>
<div class="defender">DEF</div>
<div class="defender">DEF</div>
<div class="midfielder first">MID</div>
<div class="midfielder">MID</div>
<div class="midfielder">MID</div>
<div class="midfielder">MID</div>
<div class="striker first">STR</div>
<div class="striker">STR</div>
</div>
But that does not work in IE7. You may try to investigate this a bit more.
Another idea is to use css absolute positioning. For example you add appropriate classes via jquery, so one item would have for example class="midfielder second" and you interprete this in css like "top" css style from "midfielder" class and "left" css style from "second" class.
Related
I am creating a news feed with VueJS and I have run into a bit of a problem with rendering the content. The API I am using sadly I am unable to change to suit my need properly at this time. The API gives me all the content already in HTML tags and it can also include images and lists and all the other basics. What I want to do is create a "read more" section which will render the first 20 words if just the text of the first "p" tag and stop there.
Does anyone know a quick and efficient way of doing this with JS?
My current display VueJS render is the following:
<div v-for="news_item in news_items">
<div v-bind:class="{ 'col-md-4': display}">
<div class="card">
<div class="header">
<h2>
{{news_item.title}} <small>{{news_item.subtitle}}</small>
</h2>
</div>
<div class="body" style="padding-top: 0">
<div class="row" style="margin-right: -20px; margin-left: -20px;">
<div class="col-md-12"
style="padding-left: 0px; padding-right: 0px;">
<img :src="news_item['thumbnail']"
class="img-responsive smaller-img" alt=""
style=" margin: 0 auto; max-height: 250px;">
</div>
</div>
<div class="row">
<div class="col-md-12">
<div v-html="news_item.content"></div>
</div>
</div>
</div>
</div>
</div>
</div>
This is the perfect time to use a directive:
https://v2.vuejs.org/v2/guide/custom-directive.html
See the codepen here: https://codepen.io/huntleth/pen/GOXaLo
Using the trim directive, you can change the content of the element. In the example above, it will show the first 5 words followed by an ellipsis.
If you're just after a pure js solution, this should do it:
var resultString = str.split(' ').slice(0, 20).join(" ");
You could use the trim directive and search the el for any p tags, and then change their content accordingly.
You don't appear to have tried anything yet, so I'll just give you these pointers. If you run into specific problems, ask again.
Make a component
The component should receive the html as a prop
The component should have a data item to control whether it is expanded
The component should have a computed that gets the first 20 words of the first paragraph tag. You can use textContent to get text from an HTML node.
The computed is the most likely part to pose a challenge. It will look something like this
blurb() {
const div = document.createElement('div');
div.innerHTML = this.content; // this.content is the prop
const firstP = div.querySelector('p');
const text = firstP.textContent;
const match = text.match(/(\S+\s*){0,20}/);
return match[0];
}
Rough implementation, Pure Js approach
document.getElementById("addContent").onclick = display;
document.getElementById("ellipsAnchor").onclick = hideEllipsis;
function display() {
document.getElementById("instruction").classList+= " hide";
let content = document.getElementById("inputbox").value;
if(content.length > 30) {
let sliced = content.slice(30);
let unsliced = content.substring(0,29);
let spantag = document.createElement("span");
spantag.className = "toReplace hide"
let text = document.createTextNode(sliced);
spantag.appendChild(text);
let spantag1 = document.createElement("span");
let text1 = document.createTextNode(unsliced);
spantag1.appendChild(text1);
let contentTag =document.getElementById("content");
contentTag.appendChild(spantag1)
contentTag.appendChild(spantag)
document.getElementById("ellipsis").classList -= "hide";
}
}
function hideEllipsis(){
document.getElementById("ellipsis").classList += " hide";
document.querySelectorAll("span.hide")[0].classList -= " hide"
}
.hide {
display : none;
}
<textarea type="text" id="inputbox"></textarea>
<button id="addContent">
Show content
</button>
<div id="content">
</div>
<div class="hide" id="ellipsis">
Read More..
</div>
<div id="instruction">
Type more than 30 characters and click show content
</div>
You can write a vue directive to solve this.
Set max-height to the div.
count the words and append "Read more.." link to the content.
Add a click event to 'read more' to expand the DIV to full height.
For example see this codepen
let handler = ""
Vue.directive("viewmore", {
inserted: function (el, binding){
let maxlines = binding.value
let lineheight = parseFloat(getComputedStyle(el).lineHeight)
let paddingtop = parseFloat(getComputedStyle(el).paddingTop)
let lines = (el.clientHeight) / lineheight ;
let maxheight = (lineheight * maxlines) + paddingtop + (lineheight/5)
if(lines>maxlines){
el.classList.add('vmore')
el.style.maxHeight = maxheight + 'px'
el.addEventListener('click', handler = ()=> {
el.style.maxHeight = ""
el.scrollIntoView({behavior: "smooth"})
el.removeEventListener('click', handler)
el.classList.remove('vmore')
})
}
},
unbind: function (el, binding) {
el.removeEventListener('click', handler)
handler = ""
}
});
https://codepen.io/dagalti/pen/vPOZaB .
it works based on the lines in the content.
Code : https://gist.github.com/dagalti/c8fc86cb791a51fe24e5dc647507c4a3
Expanding on the answers by tom_h and Roy J, here's what I'm using in my vue application to make the ellipsis clickable:
Vue.component("ellipsis", {
template: "#ellipsis-template",
props: ['content'],
data: function() {
return {
wordLength: 3, // default number of words to truncate
showAll: false
}
}
});
<script type="text/x-template" id="ellipsis-template">
<span v-if="content.split(' ').length>wordLength && showAll">{{content}}
(less)
</span>
<span v-else-if="content.split(' ').length>wordLength && !showAll">
{{content.split(" ").slice(0,wordLength).join(" ")}}
...
</span>
<span v-else>{{content}}</span>
</script>
To call it:
<ellipsis :content="someData"></ellipsis>
This question already has answers here:
Find a string of text in an element and wrap some span tags round it
(6 answers)
Closed 6 years ago.
I've got a loot box div in which (sometimes) the name colorful comes in.
for example:
<div id="columns">
<div id="loot">
<b>
"Loot: Colorful blade "
<br>
" slot: weapon "
<br>
" value: 7"
</b>
...more and more and more
Now if the text in the loot div contains colorful I want to add a class to the text colorful . So I thought that if the text colorful is in it, it puts a <span> around the word colorful and asign a class to it. But I cant figure out how to do this.
I tried this (jsfiddle)
Your code targets the #loot element when trying to add the rainbow class, but does it target the desired div when looking for the text in the first place? (I dont think it does, but dunno since I dont jQuery)
Here's some code to do it sans jQuery:
var tgtElem = document.getElementById('loot');
var value = tgtElem.innerHTML;
value = value.replace('Colorful', '<span class="highlight">Colorful</span>');
tgtElem.innerHTML = value;
It relies upon a css rule, .highlight - set its styles as you wish.
Here's a fully worked example:
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(id){return document.getElementById(id);}
//////////////////////////////////////////////////////////////////////////////
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
var tgtElem = byId('loot');
var value = tgtElem.innerHTML;
value = value.replace('Colorful', '<span class="highlight">Colorful</span>');
tgtElem.innerHTML = value;
}
</script>
<style>
.highlight
{
background-color: yellow;
font-weight: bold;
}
</style>
</head>
<body>
<div id="columns">
<div id="loot">
<b>
Loot: Colorful blade
<br>
slot: weapon
<br>
value: 7
</b>
<br />
<br />
<b>Current slot: weapon <br> Current weapon : Colorful blade <br> Current value: 7</b>
</div>
</div>
</body>
</html>
You need to link to the libary for the jQuery to work.
You can get it here https://code.jquery.com/
You were also correct with using the span around the word. Here is a working version
Loot: <span>Colorful</span> blade
Then target it to add the class
if ($('#loot:contains("Colorful")').length > 0) {
var str = document.getElementById("loot").innerHTML;
var res = str.replace("Colorful", "<span>Colorful</span>");
document.getElementById("loot").innerHTML = res;
$("#loot span").addClass("rainbow");
}
https://jsfiddle.net/o7phybe8/6/
EDIT: Here's the JSFiddle for the following question.
http://jsfiddle.net/x28ojg6w/
So I'm trying to activate a template with JavaScript and it wasn't working for a while, and I finally fixed it by changing a For-In loop into a For loop in a seemingly unrelated block of code.
The following code is the For-In loop I changed to a for loop. The commented out code was the original code that didn't work and the uncommented for loop is the now working code. This code was used to change font size for text within all instances of a class element:
var release4 = document.getElementsByClassName("release-4");
// for (item in release4){
// release4[item].style.fontSize = "2em";
// };
for (var i = 0 ; i < release4.length ; i++) {
release4[i].style.fontSize = "2em";
}
This is the code I used to activate my template. It is not part of the release-4 class:
var tmpl = document.getElementById('hidden');
document.body.appendChild(tmpl.content.cloneNode(true));
And here is the HTML that goes with it:
<html>
<head>
<title>Manipulate the DOM</title>
</head>
<body>
<div id="release-0">
<p class="release-4"> Here is some text, add a class "done" to the parent div</p>
</div>
<div id="release-1">
<p>remove the #release-1 div</p>
</div>
<h1>Change this text to finish release 2</h1>
<div id="release-3">
<p class="release-4"> add CSS to this div</p>
</div>
<template id="hidden">
<div>
<h1> Congrats! You finished the challenge.</h1>
<img src="http://media.giphy.com/media/2UpzC3iPenf44/giphy.gif">
</div>
</template>
<script type="text/javascript" src="home_page.js"></script>
</body>
</html>
My question is why did changing the For loop make a difference? Thanks everyone!
All other code in the JS file only affect IDs release-0, release-1, and release-3, and the h1 tag. The class name, display, innerHTML, and background color were the only changes made to them.
If I console.log() item in the for in loop it yields:
0
1
length
item
namedItem
I think length, ìtem and namedItem make it error.
Updated:
With Array.from it works as expected.
var release4 = Array.from(document.getElementsByClassName("release-4"));
for (item in release4){
release4[item].style.fontSize = "2em";
};
I am so very new to asp.net and javascript, and I am supposed to do the following task in a couple of days. I know I have to learn all the basics, before asking, but really don't know where to get what I need in short time. Thanks a lot in advance!
Here's a number cities, which will be shown on a country map:
Each city has it's own style (since city positions are different), defined in a css.
<div class="node">
<div class="taxonomy">
</div>
<div class="content">
<div id="contact_map" runat="server">
<ul>
<li id="city1" onmouseover= "onmouseoveragent(this)"
onmouseout="onmouseoutagent(this)">
<a href="someAddress"><span class="hideme">Some City Name</span>
</a>
<p class="hideme">Some City Name<strong class="tel">0123456789</strong>
</p>
</li>
<%-- other cities here, with different city name and tel --%>
</ul>
</div>
</div>
</div>
I will probably try to figure out how to create these city items dynamically later.
Below is a hint box, to be shown when mouse is over the city. It has to be repeated for all the cities. (Question1: How can I create these hint boxes dynamically, and somehow fill them with the information associated with the right city? Maybe I have to create the previous list dynamically, too..)
<div id="agentVisit" class="floating-tip-wrapper" style="margin: 0px; padding: 0px; position:
absolute; display:none; opacity: 1;">
<div class="floating-tip" style="margin: 0px;">Some City Name
<strong class="tel">0123456789</strong>
</div>
</div>
And this is tha javascript code for onmouseover and onmouseout of each city:
(Question 2: How can I tell the function which agentVisit to get? )
<script language="javascript" type="text/javascript">
function onmouseoveragent(e) {
var hint = document.getElementById("agentVisit");
console.log(hint);
hint.style.display = 'block';
hint.style.top = Math.max(e.offsetTop - hint.offsetHeight, 0) + "px";
hint.style.left = e.offsetLeft + "px";
};
function onmouseoutagent(e) {
var hint = document.getElementById("agentVisit");
hint.style.display = 'none';
}
</script>
I would appreciate it if you provide an idea (or just a general hint) of how to do it. Or just a link to a quick tutorial. Thanks!
I think you are making this way more complicated than it has to be, because you can leverage data dash (data-) attributes of DOM elements and then use something like jQueryUI Tooltip.
I'm just getting started in programming and somehow can't come up with any sensible approach to the following problem, so any help would be greatly appreciated! I have a .html file structured like this:
<head>
<title>ABC</title>
</head>
<body>
<div class="norm">
...
<span class="jnenbez">13</span>
....
<div class="Absatz">text</div>
<div class="Absatz">text</div>
<div class="Absatz">CITE HERE**</div>
The "norm" div is the one parent node. The "jnenbez" span and the "Absatz" divs are inside the "norm" div, but how deeply they are nested can vary. Now I want to cite the "CITE HERE" area, meaning to generate the output of "jnenbez 13 Absatz 3 ABC" - meaning getting the text content of the "jnenbez" span of the same "norm" div, getting the index number of the "Absatz" div, since it is the third child "Absatz" of the "norm" div and getting the content.
1) How could I give this string to the user, so he could copy paste it somewhere else? It seems it is not easily possible to modify the copy+paste behavior of Firefox. An obvious solution would be to put the output in brackets like [jnenbez...] at the end of each divs text content, but that would reduce readability of the html...
2) Is it even possible to automatically generate this output via JQuery?
Not sure about a good way to store/display the info.
Also, unsure of what other mark-up you would have in the class='norm' container. This is vitally important and impacts entirely the shape of the useful solution.
I've assumed a particular structure - one that says the first contained span is one of interest. Another assumption is that the only divs in the container are of interest and need to be counted.
I'm sure you can break it easily enough. :D
<!DOCTYPE html>
<html>
<head>
<script>
function onBtnPress(element)
{
var result;
var cont = element.parentNode;
var span = cont.getElementsByTagName('span')[0];
result = span.className + " ";
result += span.innerHTML + " ";
var divList = cont.getElementsByTagName('div');
result += divList[0].className + " ";
result += divList.length+" ";
result += document.title;
cont.getElementsByTagName('p')[0].innerHTML = result;
}
</script>
<title>ABC</title>
</head>
<body>
<div class="norm">
<span class="jnenbez">13</span>
<div class="Absatz">text</div>
<div class="Absatz">text</div>
<div class="Absatz">CITE HERE**</div>
<button onclick='onBtnPress(this);'>click me</button>
<p>[string here]</p>
</div>
<div class="norm">
<span class="Crapple">8</span>
<div class="ipod">worst</div>
<div class="ipod">music</div>
<div class="ipod">player</div>
<div class="ipod">I ever</div>
<div class="ipod">bought</div>
<div class="ipod">CITE HERE**</div>
<button onclick='onBtnPress(this);'>click me</button>
<p>[string here]</p>
</div>
</body>
</html>