Change style of multiple element groups simultaneously on hover using Angular - javascript

I find myself needing to change style of all elements that have an attribute in common (let's say a class name) when one of these elements is hovered. This is super easy to do with jQuery, like this:
$(function() {
$('.bookId4').hover( function(){
$(this).css('background-color', '#F00');
},
function(){
$(this).css('background-color', '#000');
});
});
Though I don't know how to achieve this with Angular. In this example, the elements that have the class .bookId4 are generated with Angular AJAX call, so I'd like to use Angular to create the hover effect as well. Thank you!
EDIT
To explain further, I will have many divs being generated with an AJAX call, and the div's that are in the same group will have the same class. This is the HTML code:
<div class="bookId{{ privateTour.booking.id }}"> <!-- Wrapper for hover effect -->
When one of the divs is hovered I want ALL of the divs (not only the div that is being hovered) with the same class (or some other value that they may have in common) to have a hover effect. My preferred way would be for Angular to search the whole page for all divs with a certain class name and apply a style to that class (to not have to for example generate tons of CSS for all the classes that were generated, which I'm not even sure it would work).

You can do that by using ng-mouseenter and ng-mouseleave directives, Here is the simple code, you can build on top of it to meet your requirements
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example73-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
</head>
<body ng-app="">
<h1 ng-style="myStyle" ng-mouseenter="myStyle={'background-color':'blue'}"" ng-mouseleave="myStyle={'background-color':'none'}"">Hello World</h1>
</body>
</html>

You can apply simple css solution for hover, like
.bookId4:hover {
background-color: '#F00';
}
No need for angular or jQuery :-)

Yes I agree with using ng-mouseenter and ng-mouseleave.
I did a example hope can help you
https://embed.plnkr.co/Cxfv0I9IEfBhZYj8A3zS/

use ng-class, create one scope variable which is by default false.
when mouseEnter OR mouseLeave event occurs make it TRUE/False accordingly.
<style>
.bookId4{color: red;}
</style>
<span ng-mouseenter="ctrl.hovered()" ng-mouseout="ctrl.nothovered()" ng-class="{ 'bookId4' : ctrl.ishovered==true }">soemthing 1</span>
<span ng-mouseenter="ctrl.hovered()" ng-mouseout="ctrl.nothovered()" ng-class="{ 'bookId4' : ctrl.ishovered==true }">soemthing 2</span>
<span ng-mouseenter="ctrl.hovered()" ng-mouseout="ctrl.nothovered()" ng-class="{ 'bookId4' : ctrl.ishovered==true }">soemthing 3</span>
_this.ishovered =false;
_this.hovered = function(){
_this.ishovered =true;
}
_this.nothovered = function(){
_this.ishovered =false;
}

In the end I found using an ng-class condition to be the best solution, and a variable decides what group should be highlighted. This line that I initially tried using did not work correctly:
<div ng-class="hovering == privateTour.booking.id ? 'hl' : ''" ng-mouseenter="hovering = privateTour.booking.id" ng-mouseleave="hovering = 0"> <!-- Wrapper for hover effect -->
For some reason, only the hovered div was highlighted, so I had to send the signal to a variable using a function instead for it to have a global effect. I ended up using this code for the div wrappers:
<div ng-class="hovering == privateTour.booking.id ? 'hl' : ''" ng-mouseenter="setHover(privateTour.booking.id)" ng-mouseleave="setHover(0)"> <!-- Wrapper for hover effect -->
And I wrote this simple function in the scope:
$scope.setHover = function(bookId) {
$scope.hovering = bookId;
};
And here's the style for the highlight class .hl:
.hl {
background-color: red;
}
Thank you for everyone giving the lead of ng-mouseenter and ng-mouseleave!

Related

Stop fetching the DOM element when display:none

I have a requirement and am not sure how to achieve it. I have a div with display:none and I fetch the element to show in console with document.getElementByName API. Is there a possibility that I can stop this from happening?
The expectation is if it has a display: none, null should be the query result when I access it or its children
function fetchChildToNone(){
var _ele = document.getElementsByName('test_fetch');
console.log(_ele);
}
#div2{
display: none;
}
<!DOCTYPE html>
<html>
<head>
<title> Test fetching child to a parent with display:none</title>
</head>
<body onload="fetchChildToNone()">
<div id="div1">
<span> A div to not make the page empty</span>
</div>
<div id="div2">
<span id="test_fetch" name="test_fetch"> Hello World</span>
</div>
</body>
</html>
There is actually no way to know if an element is visible or not, if you are only testing this element.
The only available way is to test offsetWidth offsetHeight if there both equals to 0 that mean two things element is on display:none or element is empty but you don't really know if you fill this element after it will keep their offset equals to 0. Moreover if your element is on visibility:hidden element's offset will not be equals to 0. So this solution is not the best.
The only way to do this nicely (without framework) is to test display and visibility of this element and all his parents.
function fetchChildToNone(){
var _ele = document.getElementsByName('test_fetch');
console.log(isVisible(_ele[0]));
}
function isVisible(elem) {
var style = window.getComputedStyle(elem, null);
if(style.display === 'none' || style.visibility === 'hidden') return false;
if(elem.parentNode && elem.parentNode.tagName !== 'body') return isVisible(elem.parentNode);
return true;
}
#div2{
display: none;
}
<!DOCTYPE html>
<html>
<head>
<title> Test fetching child to a parent with display:none</title>
</head>
<body onload="fetchChildToNone()">
<div id="div1">
<span> A div to not make the page empty</span>
</div>
<div id="div2">
<span id="test_fetch" name="test_fetch"> Hello World</span>
</div>
</body>
</html>
If you can use jQuery, then the solution is this:
$('test_fetch:visible')
Otherwise, you have to resort to this:
if(_ele.offsetWidth > 0 || _ele.offsetHeight > 0)
{
//element is visible, put your logic here.
}
Source of the solution above is here.
display: none will not prevent the browser from loading that markup and associated resources but it will prevent the browser from applying css to the the hidden div or the elements inside it. Until its display value changes, it is not rendered as part of the page flow . Basically, display: none and visibility: hidden have no impact on page load time. You need to selectively choose when to display it since that triggers a rerender of page content, and even that is usually a negligible difference in all.
I would suggest that if you want to wait to load the content until it's needed, don't include it at all or include empty divs as placeholders and then use AJAX to fetch the content from the server once it's needed after page load and add it to the page with JS. Try to use jQuery if you can as it has inbuild AJAX init.
From jQuery you can do something like this :-
$(element).is(":visible")
Bingo !! :)

Dynamic show hide code for dynamic content angular js

Run below code as it is, Code is working fine but i want the same functionality without polluting angularjs code.
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body ng-app="newapp" ng-controller="newctrl">
<div ng-repeat="x in names">
<div data-ng-click="toggleCompanyArr(['nav_' + x.id])">This is id : {{x.id}}</div>
<div id="nav_{{x.id}}" style="display:none">{{x.firstname}} {{x.lastname}}</div><br><Br><Br>
</div>
</body>
<script>
var app = angular.module('newapp',[]);
app.controller('newctrl', function($scope){
$scope.names=[
{"id":"1","firstname":"Akhilesh","lastname":"Kumar"},
{"id":"2","firstname":"Aman","lastname":"Kumar"},
{"id":"3","firstname":"Mithilesh","lastname":"Kumar"}
];
$scope.toggleCompanyArr = function(val){
$("#"+val).toggle();
};
});
</script>
</html>
You don't need to use jQuery to show/hide div, you could simply use ng-show here.
For achieving this you need to add show flag on each element of the names collection (you don't necessary to add new show property to your collection, if you don't add show: false prop in your each names element, angular will take care of this), and toggle show flag on click of the element. Thereafter use x.show flag inside ng-show directive to show & hide div.
Basically on initial load x.show value either undefined or false so anyhow it is going to hide the all element content on load. When you click on element ng-click directive will flag to x.show = true and that element will get shown.
The other advantage behind this approach is, you could have state of your each element in its object.
Suppose you have akhilesh option selected then it will have {"id":"1","firstname":"Akhilesh","lastname":"Kumar", show: true}, & other will have show: false if those element are not clicked.
Markup
<div data-ng-click="x.show = !x.show">
This is id : {{x.id}}
</div>
<div ng-show="x.show">
{{x.firstname}} {{x.lastname}}
</div>
Reference link

ASP.net UI refresh issue

I am using a checkbox and a checkbox list in one of my web pages.
The UI is like
Color - Header Checkbox
Checkboxlist items are
Red
Green
Blue
Yellow
Complete selection - clicking on the header checkbox selects/ deselects the entire checkbox list.
Partial selection of the checkbox list shows the header checkbox with a different background color to indicate partial selection.
I do a check for number of selected items in each of the checkbox list selection changes. In a client server environment, there is a time delay and if we make two continuous selections in the checkbox list, an update of the header control is done for the first selection and by the time UI is refreshed, the second selection is gone.
I also implemented the above one using JavaScript but then also the behavior is same.
What could be an alternative for this?
Your question is not particularly clear, but it sounds like you want some sort of three state check box? It also sounds like the postback is occurring and wiping out your second selection?
If so, there are some control options out there. Here's a link to one that may help. http://www.chadscharf.com/index.php/2008/10/3-state-checkbox-using-microsoft-ajax/
You really need to post some code and link to the screen shots you mention.
There are two scenarios you are trying to satisfy and the simpliest approach is utilising Javascript. Certainly one direction is using Jquery to simplify the wiring of DOM elements together.
Following is an example that kinda covers the two scenarios. One the top level control checks / unchecks all the elements. Second, the individuals change the background of the top level element. This is not drop and run code, it merely demonstrates the technique in isolation. Changes and tweaks I've leave to you + if you're unfamiliar with Jquery: simply search each function on Jquery site. Enjoy!
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
// Wire up the 'select-all' to the child elements
$('#topLevel').bind('change' , function(){
// Record this object
var base = this;
// Change the child elements
$('#checkboxContainer input').each( function(){
$(this).attr('checked' , $(base).is(':checked'))
})
});
// Make the individual checkbox selects alter the
// background of the top-level wrapper
$('#checkboxContainer input').bind('change' , function(){
// Get a handle to the top item
var topLevel = $('#topLevelWrapper');
// Have we selected the item?
if($(this).is(':checked')){
// Remove the previous class assignments
topLevel.attr('class' , '');
// Assign the current css class from the parent
topLevel.addClass( $(this).parent().attr('class') );
}
});
})
</script>
<style type="text/css">
.Red{
background-color:#F00;
}
.Green{
background-color:#0F0;
}
.Blue{
background-color:#00F;
}
</style>
</head>
<body>
<div id="topLevelWrapper">
<label for="topLevel">Top level selection</label>
<input type="checkbox" id="topLevel" />
</div>
<div id="checkboxContainer">
<ul>
<li class="Red">
<label for="topLevel">Red</label>
<input type="checkbox" />
</li>
<li class="Blue">
<label for="topLevel">Blue</label>
<input type="checkbox" />
</li>
<li class="Green">
<label for="topLevel">Green</label>
<input type="checkbox" />
</li>
</ul>
</div>
</body>

Updating the content of a div with javascript

Rather than trying to create tons of different pages on my website, I'm trying to update the content of a single div when different items in the navbar are click to update the maint div content. I tried to find a simple example using Javascript:
<script type="text/javascript">
function ReplaceContentInContainer(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
}
</script>
<div id="example1div" style="border-style:solid; padding:10px; text-align:center;">
I will be replaced when you click.
</div>
<a href="javascript:ReplaceContentInContainer('example1div', '<img src='2.jpg'>' )">
Click me to replace the content in the container.
</a>
This works just fine when I only try and update text, but when I put an img tag in there, as you can see, it stops working.
Either
1) what is the problem with how I am trying to do it?
or 2) What is a better/easier way to do it?
I'm not stuck on Javascript. jQuery would work too, as long as it is just as simple or easy. I want to create a function that will just let me pass in whatever HTML I want to update and insert it into the div tag and take out the 'old' HTML.
You just have some escaping issues:
ReplaceContentInContainer('example1div', '<img src='2.jpg'>')
^ ^
The inner ' need to be escaped, otherwise the JS engine will see ReplaceContentInContainer('example1div', '<img src=' plus some syntax errors resulting from the subsequent 2.jpg'>'). Change the call to (tip of the hat to cHao' answer concerning escaping the < and > in the HTML):
ReplaceContentInContainer('example1div', '<img src=\'2.jpg\'>')
A simple way to do this with jQuery would be to add an ID to your link (say, "idOfA"), then use the html() function (this is more cross-platform than using innerHTML):
<script type="text/javascript">
$('#idOfA').click(function() {
$('#example1div').html('<img src="2.jpg">');
});
</script>
First of all, don't put complex JavaScript code in href attributes. It's hard to read or to maintain. Use the <script> tag or put your JavaScript code in a separate file altogether.
Second, use jQuery. JavaScript is a strange beast: the principles underlying its patterns were not designed with modern-day web development in mind. jQuery gives you lots of power without miring you in JavaScript's oddities.
Third, if your goal is to avoid having to endlessly duplicate the same basic structure for all (or many) of your pages, consider using a templating system. Templating systems allow you to plug in specific content into scaffolds containing the common elements of your site. If it sounds complicated, it's because I haven't explained it well. Google it and you'll find lots of great resources.
Relying on JavaScript for navigation means your site won't be indexed properly by search engines and will be completely unusable to someone with JavaScript turned off. It is increasingly common--and acceptable--to rely on JavaScript for basic functionality. But your site should, at minimum, provide discrete pages with sensible and durable URLs.
Now, all that said, let's get to your question. Here's one way of implementing it in jQuery. It's not the snazziest, tightest implementation, but I tried to make something very readable:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery Example</title>
<style type="text/css" media="all">
/* all content divs should be hidden initially */
.content {
display: none;
}
/* make the navigation bar stand out a little */
#nav {
background: yellow;
padding: 10px;
}
</style>
</head>
<body>
<!-- navigation bar -->
<span id="nav">
about me |
copyright notice |
a story
</span>
<!-- content divs -->
<div class="content" id="about_me">
<p>I'm a <strong>web developer</strong>!</p>
</div>
<div class="content" id="copyright">
<p>This site is in the public domain.</p>
<p>You can do whatever you want with it!</p>
</div>
<div class="content" id="my_story">
<p>Once upon a time...</p>
</div>
<!-- jquery code -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script>
// Wait for the document to load
$(document).ready(function() {
// When one of our nav links is clicked on,
$('#nav a').click(function(e) {
div_to_activate = $(this).attr('href'); // Store its target
$('.content:visible').hide(); // Hide any visible div with the class "content"
$(div_to_activate).show(); // Show the target div
});
});
</script>
</body>
</html>
Ok, hope this helps! If jQuery looks attractive, consider starting with this tutorial.
Your main problem with your example (besides that innerHTML is not always supported) is that < and > can easily break HTML if they're not escaped. Use < and > instead. (Don't worry, they'll be decoded before the JS sees them.) You can use the same trick with quotes (use " instead of " to get around quote issues).

Expanding a row in a div-based table

I have a stack of <div> elements that show a name. I'd like to include a + link off to the side of each <div> that, when clicked, expands the <div> and adds more detailed information (from a RoR controller).
After poking around on the net, I found link_to_remote and related RoR stuff, but I can't seem to get the right combination to work together. Can someone point me to a tutorial or show what the controller and view interaction should look like?
Thanks!
You can do this really easily with Javascript in the example below:
<html>
<head>
<title>Text Page</title>
<script language="Javascript">
function toggleDiv(divid) {
if (document.getElementById(divid).style.visibility == 'hidden') {
document.getElementById(divid).style.visibility = 'visible';
}
else {
document.getElementById(divid).style.visibility = 'hidden';
}
}
</script>
</head>
<body>
<span onClick="toggleDiv('div1');" style="cursor:pointer;">+</span>
<div id="div1" style="visibility:hidden;">This is DIV 1</div>
<span onClick="toggleDiv('div2');" style="cursor:pointer;">+</span>
<div id="div2" style="visibility:hidden;">This is DIV 2</div>
</body>
</html>
If you set the initial visibility of the DIV's to hidden, you can use the toggleDiv function shown above to toggle the visibility of any DIV given the ID. You will probably need to tweak the style definitions for the DIVs to display next to the plus signs (put them in adjacent <TD>'s in a table for example), but I figured I'd keep it simple.
Good Luck.

Categories

Resources