started learning javascript and I'm now taking my first steps with the DOM.
I'm trying to create an accordion that has some text within each list item. The idea is when mouse is over the list item the element will show but an error for " Uncaught TypeError: Cannot read property 'display' of undefined at HTMLLIElement.show". even though I can see in the console that the variable has the elements.
window.onload = function() {
var list = document.querySelector("ul");
var listItems = document.querySelectorAll("li");
var text = document.querySelectorAll("p");
console.log(text);
for (var i = 0; i < listItems.length; i++) {
listItems[i].addEventListener("mouseover", show);
}
function show() {
if (text.style.display === "block") {
text.style.display = "none";
} else {
text.style.display = "block";
}
}
}
ul {
list-style: none;
margin-left: 30px;
width: 300px;
height: 300px;
}
li {
border: 1px solid red;
width: 298px;
height: 80px;
background-color: grey;
}
p {
display: none;
width: 299px;
height: 80px;
background-color: lightgrey;
}
<body>
<ul>
<li>
Home
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
</li>
<li>
Career
<p>Suspendisse potenti. Aenean sed ipsum libero. Praesent feugiat faucibus nisl id viverra. </p>
</li>
<li>
Contacts
<p>Nullam tristique ex eu libero sodales posuere.</p>
</li>
</ul>
</body>
You have 2 Choices :
The First One is Handling with the <p> Then you should iterate Over The All paragraph element because the text Variable is an Array !!
The Second One is Handling With li Then instead of Using text u Replace it By this and The this Keyword in This Case Will Refer to The li
First use this instead of text and the add another condition of display blank as at the first time the property is "" (empty) OR the reverse condition that checks the element is not display= none
and then you have to change the selector to querySelector of that perticular instance
window.onload = function() {
var list = document.querySelector("ul");
var listItems = document.querySelectorAll("li");
var text = document.querySelectorAll("p");
//console.log(text);
for (var i = 0; i < listItems.length; i++) {
listItems[i].addEventListener("mouseover", show);
}
function show() {
if (this.querySelector('p').style.display !== "none") {
this.querySelector('p').style.display = "block";
} else {
this.querySelector('p').style.display = "none";
}
}
}
ul {
list-style: none;
margin-left: 30px;
width: 300px;
height: 300px;
}
li {
border: 1px solid red;
width: 298px;
height: 80px;
background-color: grey;
}
p {
display: none;
width: 299px;
height: 80px;
background-color: lightgrey;
}
<body>
<ul>
<li>
Home
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
</li>
<li>
Career
<p>Suspendisse potenti. Aenean sed ipsum libero. Praesent feugiat faucibus nisl id viverra. </p>
</li>
<li>
Contacts
<p>Nullam tristique ex eu libero sodales posuere.</p>
</li>
</ul>
</body>
Related
I am trying to make #switch visible after the .content element is hovered and to make #caption disappear.
Like the element IDs suggest, the #switch element should replace the caption on hover. I used Javascript to work that out, but onmouseover and onmouseout functions did not work with .content and #caption and #switch are abruptly shifting on hover.
document.getElementById('caption').onmouseover = function() {
displaySwitch()
};
document.getElementById('switch').onmouseout = function() {
hideSwitch()
};
function displaySwitch() {
document.getElementById('caption').style.display = "none";
document.getElementById('switch').style.display = "inline-block";
}
function hideSwitch() {
document.getElementById('switch').style.display = "none";
document.getElementById('caption').style.display = "block";
}
body {
margin: 50px;
}
.content {
height: 500px;
width: 100%;
border: 3px solid black;
}
#caption {
font-size: 3em;
}
#switch {
/* The element is hidden in advance. */
display: none;
}
<div class="content">
<a id="caption">Lorem Ipsum</a>
<div id="switch">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ornare libero et vestibulum pellentesque. In accumsan et est dapibus viverra.</p>
</div>
</div>
As per your requirement 'to make #switch visible after the .content element is hovered and to make #caption disappear', added new id box to content element. And bind onmouseover and onmouseout events to box element.
Please verify the output, is it as per your requirement or I did something different?
document.getElementById('box').onmouseover = function() {
displaySwitch()
};
document.getElementById('box').onmouseout = function() {
hideSwitch()
};
function displaySwitch() {
document.getElementById('caption').style.display = "none";
document.getElementById('switch').style.display = "inline-block";
}
function hideSwitch() {
document.getElementById('switch').style.display = "none";
document.getElementById('caption').style.display = "block";
}
body {
margin: 50px;
}
.content {
height: 500px;
width: 100%;
border: 3px solid black;
}
#caption {
font-size: 3em;
}
#switch {
/* The element is hidden in advance. */
display: none;
}
<div class="content" id="box">
<a id="caption">Lorem Ipsum</a>
<div id="switch">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ornare libero et vestibulum pellentesque. In accumsan et est dapibus viverra.</p>
</div>
</div>
I am working on typing tutor. I display some data statically through an array
What I want is when user input is being matched on some given paragraph's data then paragraph's matching text's color should be changed..
i hope it will be done through DOM manipulation and tried many time but couldn't find any proper solution.
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> </script>
<style>
p{
margin-left: 200px;
width: 650px;
height: 300px;
border : 2px dashed white;
background-color: black;
color:white;
font-size:30px;
border-collapse: collapse;
}
#inputText{
width: 650px;
height: 100px;
font-size: 25px;
}
.result{
border: 2px dashed white;
margin-left: 910px;
margin-top: -339px;
width: 278px;
font-size: 25px;
height: auto;
float: right;
background-color:black;
color:white;
margin-right: 51px;
}
.time{
border: 2px dashed white;
background-color: black;
float: left;
width: 100px;
height: 100px;
border-radius: 25px;
margin-top: -343px;
margin-left: 29px;
text-align:center;
font-size:30px;
color:white;
}
</style>
</head>
<body ng-controller="myController">
<div>
<div>
<p>
<span ng-repeat="x in typingData">  {{x}}
</span>
</p>
<div style="margin-left: 200px;">
<input type="text" ng-init="count = 0" ng-keypress="check($event)" id="inputText" ng-model="getText">
<span ng-if="event.keyCode == 32">{{check()}}</span>
</div>
</div>
<div class="result">
<ul> Your speed is :{{speed}} <br/>number of Errors: {{error}}
<li ng-repeat="x in errorData">{{x}}</li></ul>
</div>
<div class="time">{{time}}</div>
</div>
<script>
var app= angular.module('myApp',[]);
app.controller('myController',function($scope,$interval,$location) {
$scope.typingData=["page","white","talk","book","follow","men","only","can","that","it","people","carry","much","kind","hear","start","begin","daily","work","and","the","lead","performance","no","place","for","him","even","most","incompetent","firm","you","could","choose","dozen","donkeys","on","they","hangling","over","a","hundred","of","pound","finance","revolution","deficit","in","your","sky","rocket"]; // statically input data it's color should be changed after matching with user input
$scope.time=0;
$scope.tempData = [];
$scope.errorData = [];
$scope.timer = function(){
$scope.time++;
$scope.speed=Math.floor($scope.word/$scope.time*60);
if($scope.time == 30){
if(confirm('Time Over')){
window.location.reload();
$scope.time = 0;
$scope.speed = '';
$scope.getText = '';
}
else{
window.location.reload();
}
}
};
$interval(function(){$scope.timer();},1000);
$scope.error = 0;
$scope.check = function($event){
var keyCode = $event.keyCode;
if(keyCode == 32){
var res =$scope.getText.split(" ");
$scope.word = res.length;
for(var i = $scope.count;i < res.length;i++){
if($scope.typingData[i] == res[i]){
//user input matching with static data
}else{
$scope.errorData[i] = res[i];
$scope.errorData;
$scope.error++;
}
res.shift();
}
$scope.count++;
}
};
});
</script>
</body>
</html>
You can use ngClass directive:
<span ng-repeat="x in typingData" ng-class="{'match': results[$index]}">  {{x}}</span>
With the CSS:
.match {
color: green;
}
And the javascript code:
$scope.error = 0;
$scope.results = []
$scope.check = function($event){
var keyCode = $event.keyCode;
if(keyCode == 32){
var res =$scope.getText.split(" ");
$scope.word = res.length;
for(var i = $scope.count;i < res.length;i++){
$scope.results.push(false);
if($scope.typingData[i] == res[i]){
//user input matching with static data
$scope.results[i] = true;
} else{
$scope.errorData[i] = res[i];
$scope.errorData;
$scope.error++;
}
res.shift();
}
$scope.count++;
};
Still, your code need some adjustments to take into account when user corrects its typing. But it gives you an idea of how to use ngClass.
DEMO
You could use ngBindHtml - Plunker
Markup
<p ng-bind-html="newParagraph"></p>
<input type="text" style="width:400px" ng-model="input">
JS
app.controller('MainCtrl', function($scope) {
$scope.paragraph = 'Mauris tincidunt aliquet sapien. Nulla metus libero, imperdiet vel ullamcorper eu, bibendum in urna. Phasellus eget suscipit felis. Aenean rutrum risus ac interdum ultricies. Maecenas egestas venenatis fringilla. In hac habitasse platea dictumst. Vestibulum auctor lorem nulla, eu maximus nibh viverra id. Morbi in bibendum nisl. Sed neque magna, ullamcorper eget molestie nec, placerat eget diam.';
$scope.newParagraph = $scope.paragraph;
$scope.$watch("input", function(newValue) {
if (angular.isDefined(newValue)) {
if ($scope.paragraph.search(newValue) !== -1) {
$scope.newParagraph = $scope.paragraph.replace(newValue, "<span>" + newValue + "</span>");
}
else {
$scope.newParagraph = $scope.paragraph;
}
}
});
CSS
span {
color: red;
}
I'm trying to do an image-based custom alert box using CSS and Javascript. I almost have it working the way I want it to. The issue that's been plaguing me is that box is sharing the overlay's transparency. Setting the box' opacity does nothing and removing the box code from its overlay "nest" makes the overlay cover the box even if the z-index is set up otherwise.
Here should be the relevant CSS Code:
#popUpDisplay {
display: none;
opacity: .8;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: lightgray;
z-index: 8;
}
#popUpTemplate {
display: none;
opacity: 1.0;
z-index: 10;
}
#popUpBackground {
display: block;
margin-top: 10%;
margin-left: auto;
margin-right: auto;
width: 495px;
height: 450px;
padding-top: 1px;
background-image: url("../images/popUp_bg.png");
text-align: center;
z-index: 10;
}
#popUpBanner {
width: 455px;
height: 86px;
margin-left: auto;
margin-right: auto;
background-image: url("../images/popUp_banner.png");
text-align: center;
}
#bannerText {
/* May switch to image */
color: white;
margin-top: 10px;
padding-top: auto;
padding-bottom: auto;
}
#popUpContent {
width: 450px;
height: 347px;
margin-top: 10px;
margin-left: auto;
margin-right: auto;
text-align: center;
}
Here's the Javascript:
function DlgShow(Message){
// Change the message.
var Msg = document.getElementById("DlgContent");
Msg.innerHTML = Message;
// Display the dialog box.
var Dlg_bg = document.getElementById("popUpDisplay");
var Dlg = document.getElementById("popUpTemplate");
Dlg_bg.style.display = "inline";
Dlg.style.display = "inline";
}
function DlgHide(){
var Dlg_bg = document.getElementById("popUpDisplay");
var Dlg = document.getElementById("popUpTemplate");
Dlg.style.display = "none";
Dlg_bg.style.display = "none";
}
And here's the HTML
<div id="popUpDisplay">
<div id="popUpTemplate">
<div id="popUpBackground">
<div id="popUpBanner">
<h3 id="DlgContent">Test Text</h3>
</div>
<div id="popUpContent">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer rutrum risus metus, a vehicula nibh molestie ac. Duis sollicitudin libero eget nunc maximus auctor. Sed eu commodo arcu. Quisque finibus pellentesque pharetra. Vestibulum quam mi, malesuada vitae sem eget, eleifend mattis nisi. Nunc ac tristique nunc. Morbi blandit justo eleifend dui malesuada, quis varius diam tincidunt. Quisque gravida posuere urna eget ultricies. Nullam ut euismod lectus. Donec congue ex quis elementum dignissim.</p>
Close
</div>
</div>
</div>
</div>
<h1>HTML Test Page</h1>
<p>This Page is strictly for testing things on a page without effecting a pre-existing page.</p>
Open
It's not pretty, and I need to work on the message displayed, but I just want to get it so it displays correctly.
This is because your content div is a child of the transparent div. (And thus inherits the opacity from #popUpDisplay.) Which is why frameworks like Bootstrap place a modal-overlay before (not around) the content div of a modal.
I would just update your CSS to use rgba on the background of #popUpDisplay:
#popUpDisplay{
display: none;
/* opacity: .8; <-- remove this */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(211, 211, 211, .8); /* <-- change this*/
z-index: 8;
}
The included snippet does almost all of what I want to do.
Click on the 'Toggle expanded' to see the elements expand to the larger size and then contract to the smaller size.
I have a few questions:
How can I contract the element whilst still filling it with text (not reducing the text to two lines until the end of the animation)?
Is it possible to achieve everything without needing to set the precise width and height in CSS that I am setting? It is currently fragile to style changes.
Is it possible to animate these boxes and have the text 'animate' as well? e.g. see the text re-wrapping as the boxes increase in size
Thanks!
$('#expand-link a').on('click', function(event) {
var $sections = $('.block');
if ($sections.data('expanded')) {
$sections.find('li').each(function() {
$(this).css('height', this.scrollHeight);
});
$sections.removeClass('expanded');
$sections.find('li').each(function() {
$(this).css('height', $(this).find('p:not(.fullview)').outerHeight() + 32);
});
$sections.removeClass('expandit');
$sections.data('expanded', false);
} else {
$sections.find('li').each(function() {
$(this).css('height', this.scrollHeight);
});
$sections.addClass('expanded');
$sections.find('li').each(function() {
$(this).css('height', this.scrollHeight);
});
$sections.addClass('expandit');
$sections.data('expanded', true);
}
});
li {
list-style: none;
background-color: white;
padding: 5px 5px 5px 5px;
margin-top: 10px;
margin-bottom: 10px;
transition: height 1s ease-in-out;
overflow-x: hidden;
overflow-y: hidden;
}
.expanded li {
width: 570px;
}
li:first-child {
margin-top: 0px;
}
li:last-child {
margin-bottom: 0px;
}
.section p {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
}
.expanded .section p {
overflow: auto;
display: block;
}
ul {
padding: 5px 5px 5px 5px;
margin: 5px 5px 5px 5px;
overflow: hidden;
}
.section p.fullview {
display: none;
}
.expanded .section p.fullview {
display: block;
}
.block {
background-color: grey;
display: inline-block;
width: 300px;
transition: width 1s ease-in-out;
}
.block.expandit {
width: 600px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="expand-link">
Toggle expanded
</div>
<div class="block">
<ul class="sections">
<li class="section">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mattis massa mauris. Fusce vel efficitur elit. Curabitur finibus sagittis nisl. Nullam luctus, magna sed feugiat scelerisque, nunc sem facilisis enim, sed ornare nulla urna sit amet
lectus. Praesent facilisis efficitur ipsum sed gravida. Mauris mollis ut nisi at fringilla. Aenean et orci libero. Curabitur pharetra odio ornare metus pharetra aliquet. Nunc nisl lorem, tempus vitae libero a, feugiat viverra dui.</p>
<p class="fullview">Some extra content</p>
<p class="fullview">A bit more</p>
</li>
<li class="section">
<p>Some different less useful text</p>
<p class="fullview">A bit of extra content for your information</p>
</li>
</ul>
</div>
I'm trying to present an jQuery accordion that is closed initially. Right now, it when you open the page, the first tab opens and I'd like it to be closed by default and opened when a tab is clicked.
Any assistance is appreciated.
<style>
#accordion {
list-style: none;
margin: 30px 0;
padding: 0;
height: 200px;
overflow: hidden;
background: #7d8d96;
width:960px;}
#accordion li {
float: left;
border-left:
display: block;
height: 170px;
width: 50px;
padding: 15px 0;
overflow: hidden;
color: #fff;
text-decoration: none;
font-size: 16px;
line-height: 1.5em;
border-left: 1px solid #fff;}
#accordion li img {
border: none;
border-right: 1px solid #fff;
float: left;
margin: -15px 15px 0 0;
}
#accordion li.active {
width: 450px;
}
</style>
<ul id="accordion">
<li>
<img src="images/section_1.png" />
<strong>Section 1 Header</strong><br/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In iaculis volutpat quam, non suscipit arcu accumsan at. Aliquam pellentesque.
</li>
<li>
<img src="images/section_2.png" />
<strong>Section 2 Header</strong><br/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In iaculis volutpat quam, non suscipit arcu accumsan at. Aliquam pellentesque.
</li>
<li>
<img src="images/section_3.png" />
<strong>Section 3 Header</strong><br/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In iaculis volutpat quam, non suscipit arcu accumsan at. Aliquam pellentesque.
</li>
<li>
<img src="images/section_4.png" />
<strong>Section 4 Header</strong><br/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In iaculis volutpat quam, non suscipit arcu accumsan at. Aliquam pellentesque.
</li>
</ul>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.easing.1.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
activeItem = $("#accordion li:first");
$(activeItem).addClass('active');
$("#accordion li").click(function(){
$(activeItem).animate({width: "50px"}, {duration:300, queue:false});
$(this).animate({width: "450px"}, {duration:300, queue:false});
activeItem = this;
});
});
</script>
Since your selector depend on a variable activeItem, you just need to define it first, and don't need to add class active to that first element.
Try this:
$(document).ready(function(){
var activeItem;
$("#accordion li").click(function(){
$(activeItem).animate({width: "50px"}, {duration:300, queue:false});
$(this).animate({width: "450px"}, {duration:300, queue:false});
activeItem = this;
});
});
Demo here
EDIT:
(to open and close)
$(document).ready(function(){
var activeItem;
$("#accordion li").click(function(){
if(activeItem == this){
$(activeItem).animate({width: "50px"}, {duration:300, queue:false});
activeItem = '';
}else{
$(activeItem).animate({width: "50px"}, {duration:300, queue:false});
$(this).animate({width: "450px"}, {duration:300, queue:false});
activeItem = this;
}
});
});
Demo here
All you need to do is this:
$(document).ready(function()
{
$( "#accordion" ).accordion({ active: false });
}
The option active set the active "panel" of the accordion if(false) no "panel" are active.
Then on click of a panel the "active" option will be set to this "panel" index.