EDIT: ( SEE ANSWER BELOW )
I've been a long time viewer of stackoverflow but my first question today since I didn't found any answer anywhere... I have a strange behavior with my javascript code. I've tried a lot of different way but never been able to correct the problem. What I want is to collapse and expand some element when I click on a button... Normally it would be simple and it's working In Chrome but not in IE8.
There is no error message
He enter the loop but do not had the class or the toggle to my element.
here is my javascript code:
function collapseClick(obj) {
var group = $(obj).attr('data-maingroup');
console.log("collapseClick on group:" + group);
console.log("obj class before:" + $(obj).attr('class'));
if ($(obj).hasClass("toggleExpand")) {
$(obj).addClass("toggleMinus");
$(obj).removeClass("toggleExpand");
} else {
$(obj).removeClass("toggleMinus");
$(obj).addClass("toggleExpand");
}
console.log("obj class after:" + $(obj).attr('class'));
$('div[data-group="' + group + '"]').each(function (index, item) {
console.log("div loop for group:" + group + " index:" + index);
$(this).toggle();
});
}
here is my Html that is rendered:
<div id="chart">
<div class="leftPart">
<div class="header">name</div>
<div class="item parent">
<a id="collapse_Integrated_Planning" onclick="collapseClick(this);return false;" style="float:left;" class="leftcollapse toggleMinus" data-maingroup="Integrated Planning"></a>Integrated Planning
</div>
<div class="item child gantShow" data-group="Integrated Planning">John Smith</div>
<div class="item child gantShow" data-group="Integrated Planning">Alex Smith</div>
</div>
<div class="gantMainControl" id="gantControl">
<div class="header">
<div class="headerRow">
<div class="headerRowYear" id="headerYear">
<div class="headerCellYear" style="width:1499.5983985355874px">2013</div>
</div>
</div>
<div class="headerRow">
<div class="headerCellMonth" style="width:126.42890508110469px">January</div>
<div class="headerCellMonth" style="width:114.1938497506752px">February</div>
<div class="headerCellMonth" style="width:126.42890508110469px">March</div>
<div class="headerCellMonth" style="width:122.35055330429486px">April</div><div class="headerCellMonth" style="width:126.42890508110469px">May</div>
<div class="headerCellMonth" style="width:122.35055330429486px">June</div>
<div class="headerCellMonth" style="width:126.42890508110469px">July</div><div class="headerCellMonth" style="width:126.42890508110469px">August</div>
<div class="headerCellMonth" style="width:122.35055330429486px">September</div>
<div class="headerCellMonth" style="width:126.42890508110469px">October</div>
<div class="headerCellMonth" style="width:122.35055330429486px">November</div>
<div class="headerCellMonth" style="width:126.42890508110469px">December</div>
</div>
</div>
<div class="container">
<div class="timelineContainer" style="width: 1503px;"></div>
</div>
<div class="container gantShow" data-group="Integrated Planning">
<div class="timelineContainer child" style="width: 1503px;">
<div class="timeline" style="width:722.9598440425635px;margin-left:772.560202716214px" title="2013/07/08 - 2013/12/31<br></div>Integrated Planning" onclick="onTimelineClick(this)" data-id="159c5c97-c135-4906-970c-e4d58f647c41" data-startdate="2013/07/08">100%</div>
</div>
</div>
<div class="container gantShow" data-group="Integrated Planning">
<div class="timelineContainer child" style="width: 1503px;">
<div class="timeline" style="width:949.2691917671041px;margin-left:546.2508549916735px" title="2013/05/14 - 2013/12/31<br></div>Integrated Planning" onclick="onTimelineClick(this)" data-id="5c3756b1-0674-4bfc-b6ce-fa765db63eed" data-startdate="2013/05/14">100%</div>
</div>
</div>
Here is my console log:
LOG: collapseClick on group:Integrated Planning
LOG: obj class before:leftcollapse toggleMinus
LOG: obj class after:leftcollapse toggleExpand
LOG: div loop for group:Integrated Planning index:0
LOG: div loop for group:Integrated Planning index:1
LOG: div loop for group:Integrated Planning index:2
LOG: div loop for group:Integrated Planning index:3
I really need help this IE8 problem begin to annoyed me a lot...
ANSWER:
I've found the answer to my question.
The problem was related with how chrome and IE handle the resize event.
I had another javascript function that was called on the resize of the browser (
$(window).resize(function () {
console.log("resize");
config.zoomLevel = ($(window).width() - 200) / 421.739; //magic formula to know how many pixel is entering in the screen for the chart.
createGantControl(('#' + mainControlId), config);
});
).
This function was regenerating my graph.
when you change css value, Chrome doesn't call the resize event.
BUT when you change css value in IE, IE recall the resize so my graph was always rerender.
Hope it can help in the futur!
-Jeff
I've found the answer to my question.
The problem was related with how Chrome and IE handle the resize event.
I had another JavaScript function that was called on the resize of the browser:
$(window).resize(function () {
console.log("resize");
//magic formula to know how many pixel is entering in the screen for the chart
config.zoomLevel = ($(window).width() - 200) / 421.739;
createGantControl(('#' + mainControlId), config);
});
This function was regenerating my graph.
When you change CSS value, Chrome doesn't call the resize event.
BUT when you change CSS value in IE, IE recalls the resize event so my graph was always rerender.
Related
I have this code that, when a certain card is clicked, its content is displayed on an overlay card. But the way I have it right now is to repetitive:
HTML:
<div class="card c1">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Owen</h3>
<h3 class="lastName">Osagiede</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c2">
<img src="max.png" width="60px">
<div class="text">
<h3 class="firstName">Kanye</h3>
<h3 class="lastName">West</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c3">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Quando</h3>
<h3 class="lastName">Rondo</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
JS:
function overlayUser(){
card[1].addEventListener('click', function(){
first.innerHTML = card[1].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[1].getElementsByTagName('h3')[1].innerHTML;
});
card[2].addEventListener('click', function(){
first.innerHTML = card[2].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[2].getElementsByTagName('h3')[1].innerHTML;
});
card[3].addEventListener('click', function(){
first.innerHTML = card[3].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[3].getElementsByTagName('h3')[1].innerHTML;
});
I have tried to loop over it with a for loop, but keep getting an error:
`function overlayUser(){
for (i = 0; i < card.length; i++){
card[i].addEventListener('click', function(){
first.innerHTML = card[i].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[i].getElementsByTagName('h3')[1].innerHTML;
});
}
}`
In a DOM event handler, the current element is this. Therefore you can write a single function for all of them:
function handleClick () {
first.innerHTML = this.getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = this.getElementsByTagName('h3')[1].innerHTML;
}
function overlayUser(){
for (i = 0; i < card.length; i++){
card[i].addEventListener('click', handleClick);
}
}
The this API is the original API for finding out which element caused the event. Thus it is very compatible with all browsers.
Alternatively, if you feel uncomfortable mixing the usage of this you can also find out the current element from the event object:
function handleClick (event) {
let card = event.target;
first.innerHTML = card.getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card.getElementsByTagName('h3')[1].innerHTML;
}
The event object is a slightly less ancient API but is compatible with everything from IE8 and above.
Additionaly you can use event bubbling/capturing to even get rid of the for loop. Just install the event on the parent element of all three cards and let event.target sort out which card caused the event:
parentDiv.addEventListener('click', handleClick);
Instead of looping over all the individual elements that you want to have event handlers and hooking each up, set a single handler on an ancestor element and allow the event to bubble up to that element. Then, when handling it, look at the event.target, which refers to the actual element that triggered the event. This is called event delegation.
Also, do not use .getElementsByTagName() in 2020. That is a 25+ year old API that returns a live node list that can dramatically hurt performance, especially since you are only interested in a single element when you use it.
Addtionally, never use .innerHTML if you can avoid it. It has security and performance implications. Since you aren't actually working with a string that needs any HTML parsed, you should use .textContent.
Finally, you should not be using h3 unless it is to create a sub-section of a pre-existing h2. Headings are meant to divide your document into ordered sections and these sections are used by those who rely on assistive technologies to navigate a document. If you are just using the h3 because of the styling the browser applies to the text, you should instead just use a p and then use CSS to style it the way you want.
// Get references to first and last (for this demo)
let first = document.querySelector(".first");
let last = document.querySelector(".last");
// Just handle the click event at the wrapper of all the cards
document.querySelector(".wrapper").addEventListener("click", function (event){
// Then access the content of the card that actaully triggered the event
first.textContent = event.target.closest(".card").querySelector("h3").textContent;
last.textContent = event.target.closest(".card").querySelector("h3:nth-child(2)").textContent;
});
/* Just for demo */
.results {
position:sticky;
left:50%;
top:0;
background-color:#e0e0e0;
border:2px solid red;
}
<div class="results">
<div class="first"></div>
<div class="last"></div>
</div>
<div class="wrapper">
<div class="card c1">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Owen</h3>
<h3 class="lastName">Osagiede</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c2">
<img src="max.png" width="60px">
<div class="text">
<h3 class="firstName">Kanye</h3>
<h3 class="lastName">West</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c3">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Quando</h3>
<h3 class="lastName">Rondo</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
</div>
This is an awkward problem, which will be better explained by looking at the live demo. Basically I have a news box populated with ng-repeat using Angular. Then I am using a jquery plugin called news ticker which allows the news headlines to move around. The first time you land on the page the news items are in their proper spots and they call the function accordingly. After moving them up or down, they stop calling the function, set a breakpoint in the code and after moving the breakpoint is never hit.
Edit - After researching this further I have found that it is because the elements need to be compiled using $compile after they're re added. However following some examples I have not gotten this to work. I need a way of compiling after a move event with this plugin.
Live demo
Angular Script for with function that should be called.
$scope.UpdateNews = function (item,number) {
console.log(item + ' ' + number);
switch (item)
{
case 'General':
$scope.NewsCast.General.Body = $scope.News.GeneralNews[number].Text;
break;
}
};
What the HTML looks like with the news boxes
<script src="http://www.jqueryscript.net/demo/Responsive-jQuery-News-Ticker-Plugin-with-Bootstrap-3-Bootstrap-News-Box/scripts/jquery.bootstrap.newsbox.min.js" type="text/javascript"></script>
<div class="row">
<div class="col-md-6 col-lg-3">
<div class="panel panel-default">
<div class="panel-heading"> <span class="glyphicon glyphicon-list-alt logo-inverse pull-left"></span><b> General News</b></div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12">
<ul class="demo1" style="overflow-y: hidden; height: 280px;" ng-model="Idk">
<li style="" class="news-item text-left" ng-repeat="item in News.GeneralNews"><strong>{{item.DateValue | date: "MMM dd yyyy"}}</strong> {{item.Preview}}<a class="FakeClickable" ng-click="UpdateNews('General',item.index)" data-target="#GeneralModal" data-toggle="modal">Read more...</a></li>
</ul>
<div ng-if="Width>768">
<div ng-include="'../pages/Modals/General/GENERAL_INLINE.html'"></div>
</div>
</div>
</div>
</div>
<div class="panel-footer"> </div>
</div>
</div>
Is there any code that I could add to the header of every page that would insert HTML at 2 or 3 points on a page (probably in the body), spread out evenly? This would be amazing for the platform that I am currently working on.
For example, maybe you wanted to embed a video using this. Ideally, I could put the code in the header, and it'd insert it 2 or 3 times in the body -- spread evenly.
Here you go: https://jsfiddle.net/westryder907/808xtyq7/
$(document).ready(function() {
$('.body > div').each(function(i, el) {
if (i % 3 === 0) {
$(this).append(" Inserted text via jQuery 2.2");
if (i > 3) {
return false;
}
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="header">
<div class="body">
<div class="region1">
Region1
</div>
<div class="region2">
Region2
</div>
<div class="region3">
Region3
</div>
<div class="region4">
Region4
</div>
<div class="region5">
Region5
</div>
<div class="region6">
Region6
</div>
<div class="region7">
Region7
</div>
<div class="region8">
Region8
</div>
<div class="region9">
Region9
</div>
<div class="region10">
Region10
</div>
</div>
</div>
Why not just edit your code and manually insert content from an external file with PHP?
I think more information is needed to fully understand why you'd want to approach this with your current method. It just doesn't make much sense to me why you would want to do it like this?
Unfortunately, I am not able to get this working in jsfiddle but maybe I overlooked something (http://jsfiddle.net/bJpyU/46/). I have blocks dynamically created and need to save the order that they are placed. Because of the dynamic fashion that this is set up, I am not able to get the index (it's always 0, and the block starting first always shows as first index wise regardless of where it is dragged). toArray and serialize are showing up as blank. I've even tried counting nth-child. Any idea how to get the order?
HTML
<div class="tab-pane active col-lg-12" id="portlet_tab_Graphs">
<div class="row padLR sortable_portlets" id="sortable_portlet_Graphs">
<div class="col-lg-4 sortable sortable_portlet_Graphs_column ui-sortable" id="102">
<div class="portlet box yellow">
<div class="portlet-title">Monthly License Revenue</div>
</div>
<div class="portlet-body clearfix pad">
<div id="h1_sortable_portlet_Graphs_102"></div>
<div id="sortable_portlet_Graphs_102">
<div class="col-lg-12 nPad">
<div class="btn-group chartToggle inline">Graph Data</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4 sortable sortable_portlet_Graphs_column ui-sortable" id="103">
<div class="portlet box blue">
<div class="portlet-title">Yearly License Revenue</div>
</div>
<div class="portlet-body clearfix pad">
<div id="h1_sortable_portlet_Graphs_102"></div>
<div id="sortable_portlet_Graphs_102">
<div class="col-lg-12 nPad">
<div class="btn-group chartToggle inline">Graph Data</div>
</div>
</div>
</div>
</div>
</div>
</div>
JQUERY
var sortdiv = "Graphs"
var blockClasses = "col-lg-4";
$(".sortable_portlet_" + sortdiv[2] + "_column").sortable({
connectWith: ".sortable_portlet_" + sortdiv[2] + "_column",
handle: ".portlet-title",
//placeholder: "dragColumn",
forceHelperSize: true,
forcePlaceholderSize: true,
start: function (e, ui) {
ui.placeholder.height(ui.helper.outerHeight());
ui.placeholder.width(ui.helper.outerWidth());
// get original block size
blockClasses = ui.item.parent().attr('class');
},
stop: function (e, ui) {
var parent = ui.item.parent();
blockWidth = blockClasses.split(" ");
parent.attr('class', function (i, c) {
return c.replace(/(^|\s)col-lg-\S+/g, blockWidth[0]);
});
//console.log(ui.position)
SavePortletDrop(sortdiv[2]);
}
});
I think the error is actually from attaching sortable to each individual item that you're sorting. It should be attached to a container div.
So, even though it looked like it was working, you were actually moving around a bunch of 1-item lists, which are always at index 0.
I got it to work like I think you want it by attaching sortable to the #sortable_portlet_Graphs. This makes ui.item.index() return the number you'd expect in the stop function.
http://jsfiddle.net/bJpyU/47/
I have a problem with my jQuery code, I want the page to slideToggle one div ones the other is clicked, the problem is that I don't want to write all the code again and again so I tried to create a code that works all the time, but I'm stuck. Box is the div which should be clicked and it should contain a class that's also used on the div that's gonna slideToggle. It should pull the class from the tab and then use it to slideToggle the right object. Please help :S (the elements are not placed close to each other which makes next or children not possible). If you have any questions - ASK!
The jQuery code of mine:
$(".box").click(function() {
var Klassen = $(this).attr("class");
$("Klassen").slideToggle(300);
});
HTML:
<!-- These should be clicked -->
<div data-toggle-target="open1" class="box ft col-lg-3">
<div class="mer">
Läs mer
</div>
<div class="bild"><img src="images/sakerhet.jpg"></div>
<h4>HöstlovsLAN</h4>
</div>
</a>
<div data-toggle-target="open2" class="box st col-lg-3">
<div class="mer">
Läs mer
</div>
<div class="bild"><img src="images/sakerhet.jpg"></div>
<h4>NyårsLAN</h4>
</div>
<div data-toggle-target="open3" class="box tt col-lg-3">
<div class="mer">
Läs mer
</div>
<div class="bild"><img src="images/sakerhet.jpg"></div>
<h4>Säkerhet</h4>
</div>
<!-- These should be toggled -->
<div class="infobox" id="open1">
<h1>HöstlovsLAN</h1>
</div>
<div class="infobox" id="open2">
<h1>NyårsLAN</h1>
</div>
<div class="infobox" id="open3">
<h1>Säkerhet</h1>
</div>
EDIT - NEW PROBLEM - STILL AIN'T WORKING!
The code didn't work in my situation and would like you to take a look at the JS-fiddle I created:
http://jsfiddle.net/Qqe89/
undefined has presented the solution.
I would warn you about using this approach, if you add any classes to the .box div then your code will break.
Instead consider using data attributes to target the div to be toggled:
<div data-toggle-target="open1" class="box green"></div>
<div id="open1">
Opens
</div>
Which can then target with
$('.box').click(function (e) {
$( '#' + $(this).data('toggleTarget') ).slideToggle(300);
});
jsFiddle with example using your html - crudely formatted sorry!
$(".box").click(function() {
var Klassen = $(this).attr("class");
$("."+Klassen).slideToggle(300);
});
class attribute may contain several classes ($(this).attr("class") OR this.className)
$("."+Klassen) will not work if there are several classes
"Klassen" does not correspond to any DOM element as there is no such tag in HTML.