ng-click anywhere on document? - angularjs

I have this login menu and its show on click but whenever i click its still open. Now i need to implement when user click anywhere on page that $scope.loginOpened = false...(to close that div with login menu)how i can do that? Any suggestion ?
This is an example of login menu:
$scope.toggleLoggedIn = function () {
$scope.loggedInOpened = !$scope.loggedInOpened;
$scope.languagesOpened = false;
$scope.loginOpened = false;
};
EDIT:
<div class="fade-show-hide" ng-show="loggedInOpened" ng-cloak>
#Html.Partial("~/Views/Shared/_LoggedInPartial.cshtml")
</div>

you can use blur()
example
<input type="text" ng-enter="doBlur($event)">
script
$scope.doBlur = function($event){
var target = $event.target;
if (!$scope.loginOpened){
// do more here, like blur or other things
$(target).blur(function() {
//do what you want here
});
}
}

If you want to hide the div you can follow the below process.
<div class="fade-show-hide" ng-hide="loggedInOpened" ng-cloak>
#Html.Partial("~/Views/Shared/_LoggedInPartial.cshtml")
</div>
<button type="button" id="btn" ng-click="toggleLoggedIn()">Hide div</button>
$scope.toggleLoggedIn = function () {
$scope.loggedInOpened = !$scope.loggedInOpened;
$scope.languagesOpened = false;
$scope.loginOpened = true;
};

Related

Show and Hide a <div> inside an ng-repeat with 'dirPagination' (AngularJS)

In this very site I've seen this question many times, but none of them works for me because of two things: I need the div to toggle when clicking the "options" button, but also to hide when clicking outside of the div; and I need it to work with dirPagination.
I saw this answer, it works fine but with one problem I just can't solve: it shows ALL the hidden divs at the same time, instead of only showing the one I clicked.
Here's my code:
<body ng-controller="MainCtrl">
<!-- pagination -->
<dir-pagination-controls
max-size="7"
direction-links="true"
boundary-links="true">
</dir-pagination-controls>
<ul>
<li dir-paginate="report in reports | itemsPerPage:4">
Options
<h3>{{report.Title}}</h3>
<div class="options" ng-show="dp">
<p>These are some options</p>
</div>
</li>
</ul>
</body>
And the JS to show the options:
//options div
$scope.showOptions = function(event){
if($scope.dp === false || $scope.dp === undefined) {
$scope.dp = true;
event.stopPropagation();
} else {
$scope.dp = false;
}
};
window.onclick = function(){
if($scope.dp){
$scope.dp = false;
$scope.$apply();
}
};
I've made a Plunker in case you wanna se it in action: my Plunker link
Can somebody help me with this issue? :(
Add a new boolean property on your reports array , for example show
var reports = [
{
"ID":1,
"Title":"Report 1",
"Show":false
},
{
"ID":2,
"Title":"Report 2",
"Show":false
}
]
Apply the property in to ng-show and also pass the current report scope object in to showOptions method to write the logic for hide and show.
<li dir-paginate="report in reports | itemsPerPage:4">
Options
<h3>{{report.Title}}</h3>
<div class="options" ng-show="report.Show">
<p>These are some options</p>
</div>
</li>
$scope.showOptions = function(event,report){
report.Show=!report.Show;
/*you can iterate through each reports and change show to false if the clicked report id not equal to report id , Angular JS will automatically update the scope in to the view*/
reports.forEach(function(item, index) {
if (item.ID !== report.ID) {
item.Show = false;
}
});
if($scope.dp === false || $scope.dp === undefined) {
$scope.dp = true;
event.stopPropagation();
} else {
$scope.dp = false;
}
};
https://next.plnkr.co/edit/hnhWMrgR3GMtVcES
You need to use a separate variable for each div you want to show. You could add the dp attribute to the report. There is no need to loop over the reports to hide them. You can just keep track of the currently visible report and hide it when another one is toggled.
Here is the relevant HTML:
<li dir-paginate="report in reports | itemsPerPage:4">
Options
<h3>{{report.Title}}</h3>
<div class="options" ng-show="report.dp">
<p>These are some options</p>
</div>
</li>
and JavaScript
var visibleReport;
$scope.showOptions = function(event, report){
if (report == visibleReport) {
report.dp = !report.dp;
}
else {
if (visibleReport) visibleReport.dp = false;
report.dp = true;
}
visibleReport = report
event.stopPropagation();
};
window.onclick = function(){
if (visibleReport) visibleReport.dp = false;
visibleReport = null;
$scope.$apply();
};
Here is a working plunker https://next.plnkr.co/edit/sWLxBGlF8D22nvYp?preview

Meteor.setTimeout() inside in Meteor.loginWithPassword()

I need help.
My code is in a login.
When the user click in login: I put a button disable to avoid that the user do click many times when the system is working, waiting for a answer
My code works fine, but I put a loader class when the user click in button login.
When the user put the password and is acepted, the system send us to the next view. This works fine, but...
The problem is:
When the user put a invalid pasword this.loadingActive = true; dont change.. the button remain with the spin active forever. I mean something happend that the variable loadingActive dont change to true
my html
<button class="btn btn-default btn-lg btn-block"
ng-class="{'disabled': login.loadingActive === false}"
ng-disabled="loginForm.$invalid || login.loadingActive === false"
ng-click="login.login()">
<span ng-hide="login.loadingActive" class="fa fa-refresh animacion-cargando"></span>
<span ng-hide="login.loadingActive">loading...</span>
<span ng-show="login.loadingActive">Login</span>
</button>
This is my js file
login() {
this.loadingActive = false;
this.error = '';
Meteor.loginWithPassword(this.credentials.email.toLowerCase(), this.credentials.password,
this.$bindToContext((err) => {
Meteor.setTimeout(() => {
if (err) {
this.loadingActive = true;
this.error = err;
} else {
this.loadingActive = true;
this.$state.go('app.pageOne');
}
}, 1000);
})
);
}
Why when I put a Meteor.setTimeout inside a Meteor.loginWithPassword happen this?
any ideas?
thanks!
I see you wrap the callback inside a this.$bindToContext. Not sure what it does but my guess is that it changes the context (this) the callback function so that this.loadingActive = true has no effect.
To fix this you could use a reference variable:
login() {
const self = this;
// ...
Meteor.loginWithPassword(
self.credentials.email.toLowerCase(),
self.credentials.password,
self.$bindToContext((err) => {
Meteor.setTimeout(() => {
// ...
self.loadingActive = true;
}, 1000);
}
));
}

angularjs : disable a button and show popup instead

I have this button :
html:
<button nav-direction="back" class="button yy" ui-sref="app.result" ui-sref-active="currentNav" ng-click="navResult()">
Board
</button>
I would like it to display a popup if a certain condition is, else I would like it to go to another page.
I need to keep the benefit of the class in ui-sref-active to show that this is the current page.
controller.js
$scope.navResult = function (){
console.log(sessionService.get('computed'));
if (sessionService.get('computed')) {
$scope.go('app.result');
} else {
//popup to user to tap on a board
//$scope.go('app.compute');
var popupConfig = {
title: 'Beware! ;)',
template: 'Tap on a board below'
};
var popup = $ionicPopup.show(popupConfig);
ClosePopupService.register(popup);
}
}
$scope.go = function ( state ) {
// console.log("go has been launched with : "+ state)
$state.go( state );
};
Simple. You just use an ng-click method instead of a ui-sref, and go to the state from there.
<button nav-direction="back" ng-class="{'your-class':classCondition}" class="button yy" ng-click="navResult()">
Board
</button>
Then in your controller....
$scope.navResult = function(){
if(something){
$scope.classCondition = false;
//code to display popup here
} else {
$state.go('app.result')
}
}
You can pass any valid state into $state.go, so if you ever want to check for a condition and perform some logic BEFORE you redirect to another page, use it inside a $scope method instead of just using the straight ui-sref.

Issue with implementing horizontal group menu in Angularjs

I am new to angularjs and was implementing a menu framework which would be both vertical & horizontal depending on a button toggle.The menu being implemented is with custom directives which looks like below.
<my-menu>
<my-menu-item></my-menu-item>
<my-menu-group label="Fruits">
<my-menu-item label="Apple"></my-menu-item>
<my-menu-item label="Orange"></my-menu-item>
</my-menu-group>
<my-menu-group label="Vegetables">
<my-menu-item label="Tomato"></my-menu-item>
<my-menu-item label="Beans"></my-menu-item>
</my-menu-group>
<my-menu>
The template for the <my-menu-group> is:
<li class="my-selectable-item" ng-click="clickedMenuGroupItem()" ng-class="{'my-item-horizontal': !isVertical()}">
<div class="acc-noselect">
<i class="fa {{icon}} my-menu-icon"></i>
{{label}}
<i ng-if="isVertical()"
class="fa fa-angle-right my-group-indicator-left" ng-class="{'fa-rotate-90':isOpen}"></i>
<i ng-if="!isVertical()" style="margin-left:5px;"
class="fa fa-angle-down" ng-class="{'fa-rotate-180':isOpen}"></i>
</div>
The link function has the code snippet as :
link: function(scope,el,attr,ctrl) {
scope.isOpen = false;
scope.closeMenu = function () {
scope.isOpen = false;
};
scope.clickedMenuGroupItem = function () {
scope.isOpen = !scope.isOpen;
if (el.parents('.my-subitem-section').length === 0)
scope.setSubmenuPosition();
ctrl.setOpenMenuScope(scope);
};
scope.isVertical = function() {
return ctrl.isVertical() || el.parents('.my-subitem-section').length > 0;
};
scope.setSubmenuPosition = function(){
var pos = el.offset();
$('.my-subitem-section').css({'left':pos.left + 20, 'top' : 40});
};
}
Vertical menu works just fine.However when the menu is horizontal if I click on 'Fruits' I get the respective list values and then when i click on vegetables both the list gets rendered.What I'm expecting is a toggle functionality.The bottom line here is that I m not able to control the scope of previously clicked element in the link function.
I've tried my best to be as descriptive as possible here.Please help ?

Knockout.js Checkbox checked and click event

We're trying to implement a checkbox and list with the following functionality:
Clicking the checkbox will either clear the array if there are items in there, or add a new item if not.
Remove an item from the array when clicking the Remove button, once the last item is removed the checkbox automatically unchecks itself.
The problem I am having is that if you click to remove each array item, then click the checkbox to add a blank entry, I'm expecting the checkbox to be checked again (as per the checked observable), however it is not?
I have the following code:
http://jsfiddle.net/UBsW5/3/
<div>
<input type="checkbox" data-bind="checked: PreviousSurnames().length > 0, click: $root.PreviousSurnames_Click" />Previous Surname(s)?
</div>
<div data-bind="foreach: PreviousSurnames">
<div>
<input type="text" data-bind="value: $data">
<span data-bind="click: $root.removePreviousSurname">Remove</span>
</div>
</div>
var myViewModelExample = function () {
var self = this;
self.PreviousSurnames = ko.observableArray(['SURNAME1', 'SURNAME2', 'SURNAME3']);
self.removePreviousSurname = function (surname) {
self.PreviousSurnames.remove(surname);
};
self.PreviousSurnames_Click = function () {
if (self.PreviousSurnames().length === 0) {
self.PreviousSurnames.push('');
}
else {
self.PreviousSurnames.removeAll();
}
alet(2)
}
}
ko.applyBindings(new myViewModelExample());
If you are using together the click and the checked then you need to return true from your click handler to allow the browser default click action which is in this case checking the checkbox:
self.PreviousSurnames_Click = function () {
if (self.PreviousSurnames().length === 0) {
self.PreviousSurnames.push('');
}
else {
self.PreviousSurnames.removeAll();
}
return true;
}
Demo JSFiddle.
You need to use a computed to monitor the length of the observable array. This way when the length reaches zero you can react to it automatically.
self.surnames = ko.computed(function() {
var checked = true;
if (self.PreviousSurnames().length === 0) {
self.PreviousSurnames.push('');
checked = false;
}
return checked;
});
Now you will have the blank text box when all of the names are cleared. If you update your binding on the checkbox it will function properly as well.
<input type="checkbox" data-bind="checked: surnames, click: PreviousSurnames_Click" />Previous Surname(s)?
FIDDLE

Resources