I'm using angularjs at my old website. And I have a problem with getting ng-if to work with multiple controls.
I have 2 icons, when I press icon A then user control A shows, when I press icon B, user control B doesn't show up.
It works if I change the order of the divs (so that user control B) is the first, but then user control A wont work. So the second one never does...
I tried remove the div containing user control A, and then user control B shows up.
I have validated so that all the booleans are correct.
I have debugged and can see that vm.showControlBisVisible is true, and I can see that the showControlAreaVisible shows up, but not the ascx file.
And last, the User Controls have exactly the same code, except for a different -tag.
EDIT: If I remove the ng-if attribute and put for example ng-if="true" then it works. Could it be that the scope doesnt update the value in the DOM or something like that? If I just write out {{vm.showControlBisVisible}} I get true.
My .aspx:
<%# Register Src="~/MyPage/UserControls/UserControlA.ascx" TagPrefix="MyPage" TagName="ControlA" %>
<%# Register Src="~/MyPage/UserControls/UserControlB.ascx" TagPrefix="MyPage" TagName="ControlB" %>
<asp:Content ContentPlaceHolderID="cphMainRegion" runat="server">
<div ng-controller="MyController as vm">
<section>
<div class="row">
<div class="small-12 columns">
<div class="row">
<div class="small-6 columns text-center">
<a ng-click="vm.showControlA()">
<span class="sprite">
<ng-include src="'/MyPage/Assets/svg/icon-A.svg'"></ng-include>
</span>
</a>
</div>
<div class="small-6 columns text-center">
<a ng-click="vm.showControlB()">
<span class="sprite">
<ng-include src="'/MyPage/Assets/svg/icon-B.svg'"></ng-include>
</span>
</a>
</div>
</div>
</div>
</div>
</section>
<section class="section--content section--gray" id="content-area" ng-show="vm.showControlAreaVisible">
<div ng-if="vm.controlAisVisible">
<MyPage:ControlA runat="server" />
</div>
<div ng-if="vm.controlBisVisible">
<MyPage:ControlB runat="server" />
</div>
</section>
</div>
</asp:Content>
My controller:
(function () {
'use strict';
angular
.module('myApp')
.controller('MyController', MyController);
MyController.$inject = ['$scope'];
function MyController($scope) {
var vm = this;
vm.showControlAreaVisible = false;
vm.controlAisVisible = false;
vm.controlBisVisible = false;
vm.showControlA = showControlA;
vm.showControlB = showControlB;
function showControlA() {
vm.controlBisVisible = false;
vm.showControlAreaVisible = true;
vm.controlAisVisible = true;
}
function showControlB() {
vm.controlAisVisible = false;
vm.showControlAreaVisible = true;
vm.controlBisVisible = true;
}
}
})();
Related
I am trying to get content to disappear on button click and then show a new set of content on that button click. I cannot quite get this to work. I commented what each section is doing. The first section doesn't disappear on button click. The second section works as expected and does disappear on button click and the third section doesn't show up on button click. Helps is greatly appreciated and I look forward to learning from this!
I thought by adding a controller it would all function together.
HTML
<!-- THIS DOESN'T DISAPPEAR ON BUTTON CLICK -->
<div ng-controller="EventCtrl" ng-hide="eventComplete">
<h2>Example that doesn't disappear on button click</h2>
</div>
<!-- THIS WILL DISAPPEAR ON BUTTON CLICK -->
<div ng-controller="EventCtrl" ng-hide="eventComplete">
<div>
<h2>Example</h2>
<md-button ng-click="eventFinish();">Finish</md-button>
</div>
<!-- THIS DOESN'T SHOW ON BUTTON CLICK -->
<div ng-controller="EventCtrl" ng-show="eventComplete">
<h2>Complete!</h2>
</div>
</div>
ANGULAR
.controller('EventCtrl', function($rootScope,$state,$scope,$timeout){
var self = this;
$scope.eventComplete = false;
$scope.eventFinish=function(){
console.log('eventFinish'); //This logs
$scope.eventComplete = true;
};
})
You wrapped the div you want to hide around the div you want to show. The following html should solve the issue:
<div ng-controller="EventCtrl">
<div ng-hide="eventComplete">
<h2>Example that doesn't disappear on button click</h2>
</div>
<div ng-hide="eventComplete">
<div>
<h2>Example</h2>
<md-button ng-click="eventFinish();">Finish</md-button>
</div>
</div>
<div ng-show="eventComplete">
<h2>Complete!</h2>
</div>
</div>
EDIT: Found an issue in controller as well. You're missing the closing } for eventFinish :
.controller('EventCtrl', function($rootScope,$state,$scope,$timeout){
var self = this;
$scope.eventComplete = false;
$scope.eventFinish = function() {
console.log('eventFinish');
$scope.eventComplete = true;
};
})
Try to avoid placing same controller inside each other. That will only lead to problems. Instead use Components.
But if you insist on using controllers you could solve it this way. (Code not tested)
HTML
<div ng-controller="EventCtrl">
<div ng-if="showExample(1)">
<h2>Example 1</h2>
<md-button ng-click="onClickExample(2);">Finish</md-button>
</div>
<div ng-if="showExample(2)">>
<h2>Example 2</h2>
<md-button ng-click="onClickExample(1);">Finish</md-button>
</div>
</div>
JS
.controller('EventCtrl', function($rootScope,$state,$scope,$timeout){
$scope.currentExample=1;
$scope.showExample = function(id){
return $scope.currentExample === id;
}
$scope.onClickExample = function(id){
$scope.currentExample = id;
}
});
I am working on an angularJS application which has a page where I display around 30 items using ng-repeat. In front of each item, there is a toggle button (enabled/disabled). With the current code that I have, I can toggle these items. But the problem is if I scroll down and toggle lets say item 25, then automatically it scrolls to the top of the page. If I now scroll down, I can see that the toggle actually took place.
So the requirement now is to make sure that the scroll position is retained after the toggle button is clicked.
Please see below the code that I have.
HTML
<div id="eventTypes" class="panel-body">
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
<div ng-if="spinner" class="spinner">
<div class="spinner-container container1">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container2">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
<div class="spinner-container container3">
<div class="circle1"></div>
<div class="circle2"></div>
<div class="circle3"></div>
<div class="circle4"></div>
</div>
</div>
</div>
JS
(function () {
'use strict';
angular.module('myApp').controller('itemsController', function ($scope, itemsService) {
var serviceError = function (errorMsg) {
console.log(errorMsg);
$scope.turnOffSpinner();
};
$scope.items = [];
$scope.item = {};
$scope.spinner = true;
$scope.toggleEnabled = function (item) {
$scope.turnOnSpinner();
itemsService.toggleEnabled(item)
.then(function () {
$scope.loaditems();
});
};
$scope.loaditems = function () {
itemsService.getitems().then(function (response) {
$scope.items = response.data;
}, serviceError);
$scope.turnOffSpinner();
};
$scope.turnOnSpinner = function () {
$scope.spinner = true;
};
$scope.turnOffSpinner = function () {
$scope.spinner = false;
};
$scope.loaditems();
});
}());
How this works right now is, once I click the toggle button, a spinner is enabled. Meanwhile the controller will call the itemService.toggleEnabled() method which does an ajax call to the server to just change the status of the item(enabled to disabled or vice-versa) in the backend. On successful change of the status and when the ajax call returns, the $scope.loadItems() method is called in the controller. This method will then do another ajax call to fetch the items (now with the updated status of the item that was toggled). The spinner is disabled and the data is then displayed on the UI.
When all of this is done, the page is scrolled to the top. This is annoying when I want to toggle an item which is way down in the list.
I want the page to be present at the same position when I clicked the toggle button of the corresponding item and not scrolling up to the top.
I am new to AngularJS and any help in this regard would be really helpful.
It looks like your spinner scheme is what's causing you problems:
...
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
...
<div ng-if="spinner" class="spinner">
...
Whenever you click your button, you are removing every single element in your ng-repeat from the DOM when you $scope.turnOnSpinner(). That's why it appears to jump to the top. It's not really jumping, there just aren't enough DOM elements to fill up the page, making the page so short that the scrollbar disappears (even if it's only for a second). Then when the spinner is done, your ng-repeat fills up the page with DOM elements again, resulting in your scroll position being lost.
So basically what you are trying to fix is a symptom of a less than ideal loading spinner implementation.
ng-if is a "brutal" way of hiding things in Angular. It's mostly meant to hide things for a longer period of time than "softer" directives like ng-show/ng-hide. One solution to your problem is to use ng-disabled on each one of your buttons to prevent the user from interacting with it while the spinner is active, rather than doing a hard removal of each element:
Before:
<div ng-if="!spinner" ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
After:
<div ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
ng-disabled="spinner"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
Another solution, which I really like and use myself is this Angular module: https://github.com/darthwade/angular-loading
You can attach it to any element in the page and it will put a loading spinner over it and prevent you from interacting with it until your ajax or whatever is done.
If you don't like either of those, try putting your ng-repeat into a container that you can use to prevent interaction with your elements when the spinner is up:
<div class="container" ng-class="{'you-cant-touch-this': spinner}">
<div ng-repeat="item in items" class="panel-body">
<div class="row">
<div class="col-md-9">{{item.itemName)}}</div>
<div class="col-md-3">
<input id="toggleEnabled"
type="button"
ng-class="{'btn-primary': item.enabled}"
value="{{item.enabled ? 'enabled' : 'disabled'}}"
ng-click="toggleEnabled(item)">
</div>
</div>
</div>
</div>
Now you can style it in some way to prevent interaction without having to remove all those items from the DOM:
.you-cant-touch-this {
pointer-events: none;
}
I'm making an app with a dynamic page. I have multiple buttons on my page but all buttons should not be visible at once rather visible one after another in consecutive. I need them to be invisible at first. For instance, the first button should be visible. When I click on that button, the button should disappear and the new button should appear and so forth. What would be the best option for implementing this using ng-show/ng-hide?
Edit--------
As for what I tried to do with them, I tried to do something like this but then I get confused with it all.:
<button style="Width: 6em;" ng-show="show" ng-click="question()">???</button>
<button style="Width: 6em;" ng-hide="hide" ng-click="question1()">???</button>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var darkness = "Darkness";
$scope.darkness = darkness;
$scope.question = function () {
var text = "Nothing but darkness and the pain that radiates through your very being.";
$scope.text = text;
$scope.hide = false;
$scope.show = !show;
}
});
I've been working on an application that shows and hides div elements. Hope you can you proceed with the following example.
<div class="container" ng-app="showHideApp" ng-controller="showHideController">
<div class="col-sm-8 col-sm-offset-2">
<!-- FORM -->
<div class="form-group">
<button class="btn btn-danger" ng-click="showMe();">Click me for show</button>
<button class="btn btn-danger" ng-click="hideMe();">Click me for hide</button>
</div>
<div class="form-group" ng-show="show">
<p>I am showing</p>
</div>
</div>
</div>
JS Code:
angular.module('showHideApp',[]).controller('showHideController', function($scope){
$scope.showMe = function(){
$scope.show=true;
}
$scope.hideMe = function(){
$scope.show=false;
}
});
I would like a directive that dynamically knows if I'm following the user in my App.
I have a resource to get the currentUser
this.following = function () {
var defer = $q.defer();
var user = $cookies.getObject('currentUser');
UserResource.get({id: user.id}).$promise.then(
function (data) {
defer.resolve(data.following);
});
return defer.promise;
};
This is in one of my services. It returns all users that I'm following.
When instantiating my controller I fetch the users I follow within my app:
UserService.following().then(
function (data) {
$scope.following = data;
});
I would like to move that into a directive so that I can easily reuse it somewhere else in my app.
This is the HTML I am using right now (and it's not really beautiful) :
<div class="item" ng-repeat="user in users">
<div class="right floated content">
<div ng-show="isFollowing(user)" class="ui animated flip button" tabindex="0"
ng-click='unFollow(user)'>
<div class='visible content'>
Following
</div>
<div class="hidden content">
Unfollow
</div>
</div>
<div ng-hide="isFollowing(user)" ng-click="follow(user)" class="ui button">Follow</div>
</div>
</div>
But instead something like :
<div class="item" ng-repeat="user in users">
<um-follow-button um-user="user"></um-follow-button>
</div>
then depending if I'm following the user or not then render one of the two options.
I don't know if I will have to use a controller in my directive.
I have looked at : https://gist.github.com/jhdavids8/6265398
But it looks like a mess.
I wanted to view different HTML pages based on what a user clicks. For example, I have three tabs set up as so:
<div class="span7" >
<ul class="nav nav-tabs" style="margin-bottom: 5px;">
<li class="active">First</li>
<li>Second</li>
<li>Third</li>
</ul>
<div class="span12" style="margin-left:0;" ng-grid="gridOptions"></div>
</div>
And I merely want to view a different page based off of what the individual clicks. For example, if he clicks First, he will see First's html page where source.sourceObject in the code below denotes which html page to view. It is written like so:
<div class="span5">
<div class="edus-activity-container">
<div ng-show="sourceViewState.selected" class="edus-admin-activities-grid" />
</div>
<div ng-include="'/partials/' + source.sourceObject + '.html'"/>
</div>
where in my javascript file, source.sourceObject is defined based off of if I click the First, Second or Third tab. However, my implementation is not working. I made sure I had no typos in the spelling of my files in source.sourceObject. Any ideas on how to do so?
In your controller:
var pages = { 'one': 'partials/one.html', 'two':'partials/two.html' }
$scope.currentPage = pages['one'] ; //This is required if you want a default page
$scope.first = function(){ $scope.currentPage = pages['one']; }
$scope.two = function(){ $scope.currentPage = pages['two']; }
In your template/HTML
<div ng-include="currentPage"/>