How to properly execute javascript against a DOM element upon ng-show? - javascript

There's a TLDR at the bottom. Otherwise here's the long-winded explanation.
I have a sort of a form, a series of various inputs that is divided into "pages" by using ng-show.
What I want is when ng-show activates and shows a new "page" and hides the old, then to execute javascript to add a class, focus, then find the input and focus on that. Essentially highlighting the next thing the user needs to do on this new page and focusing for quick input.
I've been trying to get a $watch to work but I feel like this might be over-complicating something that might have an easier alternative nor can I get it working properly.
The pages each have several divs that are questions, directions, or input elements. But when a page becomes visible, there would be one div in particular that I would highlight (see myFocusDirective placement), because some of the divs aren't actionable by the user. Example of pages:
<div id="page1" ng-show="isPage(1)">
<div>
text
</div>
<div myFocusDirective>
<input>
</div>
</div>
<div id="page2" ng-show="isPage(2)">
<div myFocusDirective>
<button>
</div>
</div>
I've been trying variations of a $watch on the attributes or using $timeout but I can't seem to accurately only match when ng-show is activated. My understanding is that it should just be applying "ng-hide" to and from the class of the div but I can't seem to match against that...
scope.$watch(function() { return element.attr('class'); }, function(newValue) {
if (newValue.match(/ng-hide/g) === null && newValue.match(/highlight/g) === null && newValue.match(/complete/g) === null) {
highlightAndFocus(element[0]);
}
},true);
also tried using $timeout on the attrs but that's unreliable due to multiple matches because of classes being applied across divs.
scope.$watch(attr.initial, function(newValue) {
$timeout(function() {
highlightAndFocus(element[0]);
});
},true);
Any help would be appreciated, I must be missing something here.
TLDR; After ng-show I want to modify the classes on a div and then focus on an input within the div

Why not make your life easier for yourself and pass the contents of your ng-show to your div as well:
<div id="page2" ng-show="isPage(2)">
<div myFocusDirective focuson="isPage(2)">
<button>
</div>
</div>
And watch the focuson in your directive scope? This way, you don’t have to worry about parent classes, etc.
But in any case, if you are watching an attr, you should be using attr.$observe

Related

Hide div if database contains value - Angular

I want to check if a postgresql database contains a specific value. If it is true I want to hide a HTML . Is this possible?
Can I hide elements with CSS & JS, or what should I use to hide the div?
Also, How would we add it in the Div like a NgIF statement
Thanks!
What you can do, vs what's best and the Angular way:
I assume you expect to have an AJAX call similar to:
$http.databaseAPI.get().subscribe(s => { this.hasValue == s.IsActive; });
Then, you could do a few things:
<div *ngIf="hasValue"></div>
Removes element from the DOM. Potentially very performance detrimental if overused.
<div [hidden]="!hasValue"></div>
Hides the element in the DOM.
<div [ngClass]="{'hideme': hasValue === false}"></div>
Changes the CSS based on an expression, and would require supporting CSS to hide the element.
Welcome to stackoverflow. You can get all that information from angular docs
*ngIf removes/adds the html elements from the html tree.
<div *ngIf="condition">Content to render when condition is true.</div>

Using jqLite to hide and show html elements

Like any normal person creating a web application using AngularJS, I initially tried using ng-hide/ng-show to make certain elements visible under certain conditions. For some reason, this doesn't want to work, and the code is too complex for me to recount it here. I figured it would be easy to use jQuery (or at least as much jQuery as Angular has built into it). This is what I have so far:
angular.element(document.querySelector([ELEMENT ID])).off();
The above line works for the purposes of hiding, but I can never get it back. In case you're wondering, I'm trying to hide buttons for otherwise unrelated actions. Using ".on()" for the code above doesn't work. How does this line need to be written in order for the element to disappear? More importantly, How do I make it reappear?
ng-show and ng-hide work with boolean values. Don't use jQuery inside the controllers. If you are needy to use that, create directives for that purpose.
Create flag variable in scope of controller. Set it to true or false
Now ng-show will show the element if it receives boolean value as true and will hide if it receives false.
Vice versa for ng-hide, it will hide if it received true and show if receives false.
So decide between either one of them, don't use both. So considering flag name is active and it is set to true and you want to show button in beginning. The code can be:
angular.module('demo', []).controller('DemoCtrl', function($scope){
$scope.active = true;
});
And the template will look like:
<div ng-app="demo">
<div ng-controller="DemoCtrl">
<button type="button" ng-click="active = false" ng-show="active">Hide Me</button>
<button type="button" ng-click="active = true" ng-hide="active">Reset</button>
</div>
</div>
We need a small css for this purpose:
.display-hide {
display: none;
}
Lets say there is an validation summary we are showing on the page;
<div class="alert alert-danger display-hide">
<button class="close" data-close="alert"></button>
<span>
#Html.ValidationSummary(false)
</span>
</div>
And with using jQuery;
jQuery(document).ready(function () {
#if(!ViewData.ModelState.IsValid) {
<text>
$('.alert span').parent().removeClass("display-hide");
</text>
}
else
{
<text>
$('.alert span').parent().addClass("display-hide");
</text>
}
});
You can use this trick for any html element.
on and off methods are not for showing/hiding elements but for adding and removing event listeners. I think by accident your element was already hidden and that led you to believe off hides element.
If you really can't use ng-hide/ng-show I suggest you use addClass and removeClass (instead of off and on) to add/remove 'hidden' class to your element. This class could would set the elements display to none.
However I encourage you to show the angular code so we can help you solve this using ng-show.

How do I make display:none to display:block elements not take up its original space in DOM?

I have this sample snippet: https://jsfiddle.net/uyg8tauo/ wherein several divs are initially defined as display: none; and upon clicking the buttons, I would like them to appear by changing the display property of the element to block.
However, I would like the elements to cascade properly based on the buttons I actually clicked. For instance, if I click the the first button 4 times, the elements with ids "school_" + n show up one after another and if I click on the second button the div with id "noSchool_" + n appears after the first ones not on where it is exactly written on my DOM.
Please take note that it has to be supported by legacy browsers (IE8<). Apparently, my divs have to pre-defined and cannot be dynamically added. I really hope I made myself clear with my problem and any feasible solution is greatly appreciated!
Thanks.
If you re-append a DOM element into it's same container, it will be put last in the DOM tree. Consider the following:
<div id="container">
<div id="button-1">1</div>
<div id="button-2">2</div>
<div id="button-3">3</div>
</div>
Now, if you would do this:
document.getElementById('container').appendChild(document.getElementById('button-1'));
This would effectively switch the DOM into the following structure:
<div id="container">
<div id="button-2">2</div>
<div id="button-3">3</div>
<div id="button-1">1</div>
</div>
As explained in the first paragraph here:
https://developer.mozilla.org/en/docs/Web/API/Node/appendChild

How to manipulate DOM after ng-show in Angularjs?

I'm new to angularjs. I'm using angularjs version 1.2.13.
I've come upon a scenario where after ng-show displays my DIV, I need to manipulate the DOM in order to realign some DIV columns. I cannot realign my DIVs if they are hidden.
HTML looks like this:
<div ng-controller="MyController" ng-show="IsThisShown">
<div class="column">1</div>
<div class="column">2</div>
<div class="column">3</div>
</div>
I think the way to go would be to create a "realign" directive such as:
<div class="column" realign>1</div>
<div class="column" realign>2</div>
<div class="column" realign>3</div>
But I'm not sure how I would make the directive trigger only when the parent DIV is shown (through the ng-show directive).
Any ideas ?
Thanks appreciated!
Here's a little more code:
module.controller("MyController", function($scope, FormState){
$scope.$watch(function(){ return FormState.showGrid; }, function(newVal, oldVal){
//At this point in time, right here, the DOM has not been updated...
$scope.IsThisShown = newVal;
//At this point in time, right here the DOM has still not been updated...
//the DOM gets updated when the function exists
});
});
You have a few different options.
One option you can explore is using an isolate scope with your realign directive.
See this example here:
http://plnkr.co/edit/lO2U4GZcEm4K1qGLpsFV
You don't have to use the isolate scope as Angular scope is prototypical by nature (though with a slight gotcha with regards to primitives), but I figured I'd throw this into the example so you can see isolate scope in action. In this example I'm using an isolate scope with an execute expression.
Just a random example that builds on your description by randomly repositioning some div's after the parent is shown.
Hopefully that helps.
There are a lot of ways, but the way that immediately comes to mind is:
<div ng-controller="MyController" ng-show="IsThisShown">
<div class="column" realign="IsThisShown">1</div>
<div class="column" realign="IsThisShown">2</div>
<div class="column" realign="IsThisShown">3</div>
</div>
And have your new directive observe its argument and do the realignment when it goes true.
The other answers are good (and standard), but tie the realign directive to being shown/hidden by that variable. If, for example, there are two nested ng-show's, this would break down. In my opinion, a better solution is to create an on-show directive, with the following scope:
scope: { 'onShow' : '&' }
And within the link function, set up a $scope.$watch as follows:
$scope.$watch(
function() { return $element.hasClass('ng-hide'); },
function(newVal, oldVal) { /* execute onShow here if newVal === false */ }
);
You could also (and I don't recommend this) change ng-show to ng-if. ng-if removes and adds the elements from the DOM, instead of just hiding them. In that case, the link function fires every time the element reappears.

write custom function for navigation angularjs

So I have a navigation that I want to have a dropdrown menu with sub-menu functionality on it. I tried ng-show for showing and hiding the menus but then I would have to go back and click on item again to hide it. I want to be able to click to show, then click anywhere else to hide it.
trying to use ng-click but not sure where I should put my custom function that I want to retrieve regardless of the controller being used.
Would I put something like this in a directive? The function is not calling html or getting any content like a factory is generally for, it simply shows and hides content on different click events.
There are probably more complicated ways of doing this that might be more elegant, but I've found this to do the trick in the past. Assumes you're loading jQuery before Angular so $ is full jQuery. If you're finding yourself doing this with many different DOM elements though, it might be more effective to break this out into a factory that allows many objects to register themselves in this way with just one binding to body.
app.directive('clickOffHide',function() {
return {
...
link: function(.., elem, ..) {
$('body').click(function(evt) {
var $elem = $(elem);
var $target = $(evt.target);
if($elem.is($target) || $elem.has($target).length > 0) return;
$elem.hide();
});
}
}
});
You could try using ng-blur on the drop-down element.
<div ng-class="dropDown" ng-blur="functionToHideElement" tabindex="100">Products</div>
A div element can accept a blur event if it has a specified tabindex.
This way you can use a baked in Angular directive rather than creating your own.

Categories