Angularjs toggle panel & sub-panel controls - angularjs

there are multiple panels and sub-panels (DIVs), that i need to show its (panel) controls on click to do specific tasks. The project is cv builder with front-end editing capabilities. So in regard to show/hide panels, my approach is very basic so hoping there would be much better way to getting this done.
Here is HTML Markup
<div class="panel component-about" ng-class="{'active': aboutPanel}" ng-click="activePanelAbout()">
<h2 class="title">Some Title (input)</h2>
<div class="panel-body">
Some text (textarea)
</div>
<div class="panel-hover-controls">
<span class="fa fa-pencil"></span>
<span class="fa fa-cog"></span>
<ul class="panel-dropdown" ng-class="{'active': aboutToggle}">
<li><label class="input-switch"><input type="checkbox" ng-model="aboutTitleShow" ><span class="slider round"></span></label> Show Title</li>
</ul>
</div>
</div>
<div class="panel component-experience" ng-class="{'active': expPanel}" ng-click="activePanelExp()">
<h2 class="title">Some Title (input)</h2>
<div class="panel-body">
<ul class="panel-componenets">
<li ng-repeat>
Title
Content
</li>
</ul>
</div>
<div class="panel-hover-controls">
<span class="fa fa-pencil"></span>
<span class="fa fa-cog"></span>
<ul class="panel-dropdown" ng-class="{'active': aboutToggle}">
<li><label class="input-switch"><input type="checkbox" ng-model="aboutTitleShow" ><span class="slider round"></span></label> Show Title</li>
</ul>
</div>
</div>
<div class="panel component-skills" ng-class="{'active': skillsPanel}" ng-click="activePanelSkills()">
<h2 class="title">Some Title (input)</h2>
<div class="panel-body">
<ul class="panel-dropdown" ng-class="{'active': aboutToggle}">
<li><label class="input-switch"><input type="checkbox" ng-model="aboutTitleShow" ><span class="slider round"></span></label> Show Title</li>
</ul>
</div>
<div class="panel-hover-controls">
<span class="fa fa-pencil"></span>
<span class="fa fa-cog"></span>
<ul class="panel-dropdown" ng-class="{'active': aboutToggle}">
<li><label class="input-switch"><input type="checkbox" ng-model="aboutTitleShow" ><span class="slider round"></span></label> Show Title</li>
</ul>
</div>
</div>
Further please check markup figure in (below) screenshot.
In reference to attached screenshot, there are multiple panel sections and most of panels also have sub-panels and each panel has its own control type which need to be show on click.
Here is JS (Controller)
// for setting popups
$scope.aboutToggle = false;
$scope.expToggle = false;
$scope.skillToggle = false;
// about panel
$scope.activePanelAbout = function() {
$scope.aboutPanel = true;
$scope.expPanel = false;
$scope.skillPanel = false;
}
// experience panel
$scope.activePanelExp = function() {
$scope.aboutPanel = false;
$scope.expPanel = true;
$scope.skillPanel = false;
}
// skill panel
$scope.activePanelSkill = function() {
$scope.aboutPanel = false;
$scope.expPanel = false;
$scope.skillPanel = true;
}
Now i think the picture should be clear. The panels are toggling actually, but i require more better approach something like this that we use to do in javascript/jquery.
I hope i have covered all aspects of my question, if not please do guide me so i can clarify myself. I'm looking forward for your guidance.
Thanks in advance.

this in AngularJS ends up a bit different than plain old JS. Since a controller contains its own $scope in relation to the DOM of which the controller is instantiated, this doesn't always refer to the object that calls a function, etc. So I can think of two options:
First maybe simplify how you're changing the active class for each panel and it's children. So maybe just:
$scope.activePanel = "";
$scope.ChangeActivePanel = function(newPanel) {
$scope.activePanel = newPanel;
}
And then change the ng-class for each panel to ng-class="{'active': activePanel == 'about'}" or ng-class="{'active': activePanel == 'skills'}", etc. Then change ng-click on the panels to ng-click="ChangeActivePanel('about')" or whatever to update the variable. In all honesty, just ng-click="activePanel = 'about'" would work but the ChangeActivePanel function could be expanded to handle behavior of the children panel elements as well. Just a thought rather than having three different functions and toggling all of these variables.
Second option is to create controllers for each panel by declaring ng-controller="aboutController" or ng-controller="skillsController" to each panel and then each panel would have it's own $scope but you'll have to declare and attach each controller to the app module and you'll run into headaches if you need to share data across controllers and will have to use factories/services, etc. I think that's overkill for something like this. Plus, it's difficult to manage which $scope is which across multiple controllers within the same view.
Hopefully this gives you something to work with.

Related

How to bind a part of a variable already binded

I have a loop ng-repeat that displays sevral icons.
<div class="box">
<div class="box-body">
<div class="row" >
<div class="col-sm-6" style="margin-bottom: 5px;" ng-repeat="record in newlayout.display" align="center">
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
<span class="badge bg-yellow" style="font-size:22px;">{{record.numberOfSamples}}</span>
<i class="fa fa-{{newlayout.labStyle}}"></i> {{record.lab}}
</a>
</div>
</div>
</div>
</div>
My issue is that the second part of the binded variable itemValue should be dynamic
In my Js, I have this
newLayout.url = 'sublabs/?labName=';
newLayout.itemValue = 'record.lab';
The URL is dynamic.
When I click on the first displayed Icon, the url should look like this :
But it didn't work as I had a compilation error..
Does someone have an idea how to fix this:
http://localhost:8181/#/newlayout/sublabs?labName=PIA/C1 - Shiftlabo
Where the record value "PIA/C1 - Shiftlabo" change.
So basically here if I change
<a class="btn btn-app" ng-href="#newlayout/{{newlayout.url}}{{newlayout.itemValue}}" >
{{newlayout.itemValue}} by {{record.lab}} it would work..but the {{record.**lab**}} should be dynamic as it will have another value when I click on the icon. It will change to {{record.subLab}}
Thanks
Use property acccessor bracket notation inside the binding:
<div>{{record[labOrSublab]}}</div>
JS
var isSublab = false;
$scope.labOrSublab = "lab";
$scope.clickHandler = function() {
isSublab = !isSublab;
$scope.labOrSublab = isSublab ? 'subLab' : 'lab';
};

In what scope is ng-repeat "as alias" available

I'm using angular 1.4.8. I want to save filtered result from ng-repeat and use it to determine whether to enable a "load more" button at the bottom of the list. I have looked at this question:
AngularJS - how to get an ngRepeat filtered result reference
And many others, they suggest to use "as alias" from ng-repeat, here's what my code looks like:
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in items | limitTo: totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
{{filteredResult.length}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="totalDisplayed <= filteredResult.length">
more
</button>
However, I found filteredResult.length is displayed fine right after ng-repeat, but the button is never shown. If I try to display filteredResult.length in where the button is, it will show null.
So is there a rule for "as alias" scope? I've seen plenty of examples work but mine doesn't, what am I missing here?
EDIT:
The accepted answer uses controllerAs which indeed will resolve the problem. However, charlietfl's comment using ng-init to save filteredResult to parent scope is also very neat and that's the solution I use in my code eventually.
Probably some of classes in your <ul class="media-list tab-pane fade in active"> or <li class="media"> is selector for a directive that would have its own scope. So you store filteredResult in e.g. tab-pane's scope and then try to have access out of it's scope in outside of ul tag.
Try to use Controller as instead of scope:
angular
.module('plunker', [])
.controller('MainCtrl', function() {
vm = this;
// make an array from 1 to 10
var arr = [];
while (arr.length < 10) {
arr.push(arr.length + 1)
};
vm.items = arr;
vm.totalDisplayed = 5;
vm.filteredResult = [];
});
<body ng-controller="MainCtrl as main">
{{main.items}}
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in main.items | limitTo: main.totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
filteredResult = {{main.filteredResult = filteredResult}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="main.totalDisplayed <= main.filteredResult.length">
more
</button>
</body>
http://plnkr.co/edit/drA1gQ1qj0U9VCN4IIPP?p=preview

$scope is only visible in function and thats why is not working

My layout page looks like this:
<li class="dropdown">
<ul class="submenu">
<li>#Translate("MY_ACCOUNT")</li>
</ul>
</li>
In layout page i have : #RenderBody()where i have Index page.In index page im using <div ng-view></div>. What im trying to do is when user click on a href to redirect him on that page and set class to this menu that is render in ng-view:
<div class="account-item">
<div class="account-heading" ng-class="{active : activeMenu === 'Settings'}">
<h4 class=" account-title has-sub">
<a data-toggle="collapse" data-parent="#accordion" href="#settings" ng-click="activeMenu='Settings'">5. #Translate("SETTINGS")</a></h4>
</div>
<div id="settings" class="account-collapse collapse in">
<div class="account-body">
#Translate("PERSONAL_INFORMATION")
#Translate("NOTIFICATIONS")
#Translate("CHANGE_PASSWORD")
#Translate("GAME_SETTINGS")
</div>
</div>
</div>
When i try this nothing happens:
$scope.SetActiveMenuForPersonalInfo = function () {
$scope.activeMenu = 'Settings';
$scope.activeLink = "PersonalInfo";
}
$scope.activeMenu and $scope.activeLink are visible only in function and thats why i cant set class on menu. When i put it out of function it works
Try changing the tripple equality sign in ng-class="{'active-link' : activeLink==='PersonalInfo'}" to double ==
PS: I do not understand the last paragraph

How to show tab with carousel avoiding sliding from the current image to the selected image?

In my Angular app I have a simple twitter-bootstrap carousel, in a tab:
<div class="tabbable">
<ul class="nav nav-pills">
<li ng-class="{active: tabSelected === 'main'}">
Main
</li>
<li ng-class="{active: tabSelected === 'photos'}">
Photos
</li>
</ul>
</div>
...
<div class="tab-content" ng-show="tabSelected === 'photos'>
<div class="slides-control">
<carousel disable-animation="false">
<slide ng-repeat="photo in person.photos" active="photo.active">
<img class="slide" ng-src="{{photo.path}}" />
</slide>
</carousel>
</div>
</div>
In the controller I have defined a method, tabSelect(tabName, photoNumber), which allows the tab to be selected in code, and - if the tab is the one named 'photos' - a specific image number can be selected:
<script>
$scope.tabSelect = function (tabName, photoNumber) {
if (tabName === 'photos') {
$scope.person.photos[0].active = false;
$scope.person.photos[photoNumber].active = true;
}
$scope.tabSelected = tabName;
};
</script>
The problem is this:
When calling, for example, $scope.tabSelect('photos', 7);, the photos tab is shown, but initially the previously active image is shown, and then immediately it slides to the selected image (the 7th, in the example). I don't want to avoid using animations, which are quite cool... Though, I want to display immediately the selected image...
I did already try to surround the $scope.tabSelected = tabName; instruction in a $timeout() block, and the selected slide is immediately shown, but not fully rendered (for example, the arrows are not present...).

Angular drag and drop

I have two simple lists that I can drag my questions to and from. Each time I drag one of the questions it changes its "Active" status to true or false:
$scope.onDrop = function ($event, $data, array) {
if ($data.Active) {
$data.Active = false;
array.push($data);
}
else if (!$data.Active) {
$data.Active = true;
array.push($data);
}
};
This works great but I need to restrict the user from being able to drag and drop into the same list as they are dragging from since that also triggers the onDrop function.
I'm using : http://angular-dragdrop.github.io/angular-dragdrop/
I have just started out with drag and drop but from what I can tell of the documentation is that I have to use the drag-channel/drop-channel attributes , however I am having a hard time understanding how they actually work.
In my markup I have two panels like so:
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Aktiva frågor
</div>
<div class="panel panel-body">
<ul class="dnd"
drag-channel="A"
drop-channel="A"
ui-on-drop="onDrop($event,$data,activeQuestions)">
<li ui-draggable="true" drag="aquestion"
on-drop-success="dropSuccessHandler($event,$index,activeQuestions)"
ng-repeat="aquestion in activeQuestions track by $index">
{{aquestion.Name}}
</li>
</ul>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Inaktiva Frågor
</div>
<div class="panel panel-body" >
<ul class="dnd"
drag-channel="B"
drop-channel="B"
ui-on-drop="onDrop($event,$data,inactiveQuestions)">
<li ui-draggable="true" drag="iquestion"
on-drop-success="dropSuccessHandler($event,$index,inactiveQuestions)"
ng-repeat="iquestion in inactiveQuestions track by $index">
{{iquestion.Name}}
</li>
</ul>
</div>
</div>
</div>
I have tried all kinds of combinations of A and B but none are working so obviously I seem to not understand the logic of them.
Or if this is not the best way to attack the problem please let me know of a better way. :)
Solved it by moving the Active logic into my code behind instead.

Resources