Bind different dom elements in Angular - angularjs

I have this HTML
<div class="pageContent">
<aside class="left-cont">
<ul class="btn-menu" >
<li ng-repeat="tab in tabs" ><a class="ng-scope ng-binding" href="#" ng-click="show={{tab.id}}"> {{tab.name}}</a> </li>
</ul>
</aside>
<section class="main-content" ng-show="show === 1">
<h1> {tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
<section class="main-content" ng-show="show === 2">
<h1> {{tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
<section class="main-content" ng-show="show === 3">
<h1> {{tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
</div>
And I have three problems with it:
1)ng-click="show={{tab.id}}"shows me the right id number in the dom, for instance, id=1 does show <a class="ng-scope ng-binding" href="#" ng-click="show=1">but I do get an error in my console - Error: [$parse:syntax] http://errors.angularjs.org/1.3.8/$parse/syntax?p0=%7B&p1=invalid%20key&p2=7&p3=show%3D%7B%7Btab.id%7D%7D&p4=%7Btab.id%7D%7D Why is that? I have tried to to write tab.id instead of {{tab.id}}, but it doesn't even fetch the element.
2) I want the section tags to be appended whenever there's a click on the a, but I can not do so since the section tags aren't wrapped in the li tags (when I do put them in the li they do fire, but that's not what I want). How do I bind these two different elements?
3) I want each section to append the content of its specific tab for the section that has - ng-show="show === 1" I want tab.title and tab.content of the tab that has the id=1, and so on..
How is that all possible?
Help is very much appreciated here

#HarishR is right: this is not the AngularJS way to do things. The imperative way of doing things would be to have an ng-click set the isActive property to true on an instance of tab.
Then the directive would would watch the isActive property and change class accordingly.
Since you probably don't want to reinvent the wheel, you could consider using Angular strap ( http://mgcrea.github.io/angular-strap/#/tabs#tabs ) or check out this code https://github.com/angular-ui/bootstrap/blob/master/src/tabs/tabs.js.

Related

ng-class not working in one situation. What are some possible cause of this?

I'm stuck. Cannot figured this out. This question is very simple to show, but I'm not really sure how to put it as a question, therefore I'll try my best.
First, here's the layout of my whole app (The problem lies in the Header.jsp):
<jsp:include page="../home/Header.jsp" />
<jsp:include page="../home/Modals.jsp" />
<div data-ng-view data-save-scroll-position data-position-relative-to-menu></div>
<jsp:include page="../home/Footer.jsp" />
The problem is very simple. I have the following data-ng-class in the data-ng-view section that change a tab to active if something is true (The problem is it won't work in one scenario even though it displayed true in the tab name):
<ul class="nav nav-tabs">
<li role="presentation" data-ng-class="tab.isSelected ? 'active' : ''" data-ng-repeat="tab in ctrl.tabs"
data-ng-click="ctrl.fetchBIReports(tab)">
</li>
</ul>
In the JSP that use data-ng-include for the above markup, there's a side nav to change to this page. Once clicked this side-nav, it highlighted the tab 'active' as expected (trying not to include the whole jsp):
<div class="side-navbar">
<ul>
<li class="{{ ctrl.navigate.path == 'bi/schedule' ? 'active-link' : 'normal-link'}}">
Schedule Reports
</li>
</ul>
</div>
<div class="content-right" data-ng-include="ctrl.navigate.path"></div>
content-right includes the JSP mentioned in the second markup.
So far, so good. Here's a demo of it working (including both side-navbar and content-right):
The problem is, in my Header.jsp, there's a nav bar that takes me to the same page. If it is clicked from a different page with different controller, then it works. But if I'm in the current controller and click that nav bar link, then data-ng-class does not take 'active' as its class. Here's the markup for the Header.jsp for that link:
<li class="dropdown" data-roles="['ROLE_ADMIN']">
<a href="#/bi" class="dropdown-toggle" data-toggle="dropdown" data-ng-click="ctrl.changeNavigation('bi/schedule')"
role="button" aria-haspopup="true" aria-expanded="false">BI Management<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>Schedule Reports</li>
</ul>
</li>
Here is the demo of it not working even though it is printing out true in the UI:
The only problem is with this UI. All the data are populated. Records are displayed for the correct tab. Even side nav-bar is displaying the correct active class.
Your syntax for ng-class is off a bit. The format is "{ '[class-name]': [expression that evaluates to true or false] }". You can have multiple class values separated by commas each with their own expression. When an expression is true, the corresponding class is applied to the element and when it is false the class is removed from the element. The way you have written it would almost work for the plain class attribute, but you would need to include the interpolation characters: {{ and }}. Here is a very simple example to illustrate ng-class.
angular.module('app', []);
.red {
color: #fff;
background-color: #e21d1d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app">
<label>
<input type="checkbox" ng-model="applyRedClass" /> Apply 'red' class
</label>
<div ng-class="{'red': applyRedClass}">
This is a simple example of how to use ng-class.
</div>
</div>

toggle extra detail for a record inside an ngRepeat

I'm working on a project where the client has supplied a pile of html where I need to plugin the data from our database and have hit a problem that I'm finding difficult to solve....
So first problem is with routing
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information collapse">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
he has supplied some javascript to handle the click on class-overview
$('.class-overview a').on('click',function(e) {
e.preventDefault();
});
$('.class-overview').on('click',function() {
$('.class-overview.active').removeClass('active').next('.class-information').collapse('hide');
$(this).addClass('active').next('.class-information').collapse('show');//.css('top',offset).collapse('show');
});
and i have a line like this in my state provider
// default route
$urlrouterProvider.otherwise("/")
So the problem is that the ui-router handles the click and sends me back to the home page.
The ideal solution is to leave as much of his markup intact, so can anyone tell me how I stop ui-router handling the click?
or failing that, how I might use ng-click and ng-show to get the same effect, i.e. hiding and showing the class-information div...
If I understand well your question, you want to display the .class-information div when you click on the .class-overview element.
That can be done by using a variable in a ng-show like this:
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#" ng-click="display = !display">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information" ng-show="display">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
The display variable will be falsy when you land on the page, therefore the ng-click will be executed, this variable will be set to true.
I see that you are using a collapse class to hide the content if it is collapsed. Then you could use angular ng-class to put the collapse class when the display variable is false. Your div.class-information would look like this:
<div class="class-information" ng-class="{collapse: !display}">
<div class="full-width">
{{class.longDescription}}
</div>
</div>

AngularJS: drag-and-drop directive

I want do some modification with code or with directive to allow:
Limit dragging only vertically(by Y axis)
Make possible to pick up item for dragging only in one place of the
element.
I'm using implementation of this directive. https://github.com/marceljuenemann/angular-drag-and-drop-lists
<ul dnd-list="list.value"
class="list-group"
dnd-allowed-types="['entry']"
dnd-dragover="overItem()"
>
<li ng-repeat="entry in list.value"
dnd-draggable="entry"
dnd-moved="list.value.splice($index, 1)"
dnd-effect-allowed="move"
dnd-type="'entry'"
dnd-dragstart="selectedItem(entry, list.value)">
<div>
<div class="numeric-column">{{$index + 1}}</div>
<div class="col-md-5">{{entry.id}}</div>
<div class="col-md-5">{{entry.name}}</div>
</div>
</li>
</ul>
This code working fine.
Question: can i restrict li element to move only verticaly.
Example: http://jqueryui.com/draggable/#constrain-movement

Trouble with active tab default using AngularJS, UI Boostrap, and UI Router

When using a UI Boostrap tabset along with nested sticky states created with ui-router and ui-router-extras, I have an issue where navigating to a tab's state via URL will select the first tab along with the correct tab. It should only activate the tab whose state matches the URL route.
Here's what the tabset looks like:
<div style="position:relative">
<tabset>
<tab heading="Dashboard" ui-sref="LMS.Dashboard" ui-sref-active="active"></tab>
<tab heading="Modules" ui-sref="LMS.Modules" ui-sref-active="active"></tab>
<tab heading="Messages" ui-sref="LMS.Messages" ui-sref-active="active"></tab>
<tab heading="Settings" ui-sref="LMS.Settings" ui-sref-active="active"></tab>
</tabset>
<div ui-view="Dashboard" class="tab-content" ng-show="$state.includes('LMS.Dashboard')">
<h2>Dashboard</h2>
{{test}}
</div>
<div ui-view="Modules" class="tab-content" ng-show="$state.includes('LMS.Modules')">
<h2>Modules</h2>
</div>
<div ui-view="Messages" class="tab-content" ng-show="$state.includes('LMS.Messages')">
<h2>Messages</h2>
</div>
<div ui-view="Settings" class="tab-content" ng-show="$state.includes('LMS.Settings')">
<h2>Settings</h2>
</div>
</div>
I have a plunker here:
http://plnkr.co/edit/sQB58YKntDwNIUpAdLmT?p=preview
To see the issue, select a tab other than 'Dashboard', then reload the "live view" frame.
Another way is to open it in a window, switch the tab, then reload.
I have the same issue. Add active="false" to disable default behavior and use ui-sref-active to add active class.
<tab ui-sref-active="active" active="false">
Edit
While this method seems to works, it produces error because false is not assignable.
Edit 2
Combining ng-init with a local scope variable seems to do the trick.
<tab ui-sref-active="active" active="isActive" ng-init="isActive=false">
In your case, it might be simpler to just add an active variable for each tab. See this plunker:
http://plnkr.co/edit/73lm068buZf851h47FVQ?p=preview
I had exactly the same thing. After searching for while, I decided the "value" ui-bootstrap offers around tabs is not worth the effort. My simple manual implementation:
<ul class="nav nav-tabs">
<li ng-class="{active:$state.current.name == 'properties.edit.basic'}"><a ui-sref="properties.edit.basic">Basic</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.marketing'}"><a ui-sref="properties.edit.marketing">Marketing</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.rooms'}"><a ui-sref="properties.edit.rooms">Rooms</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.images'}"><a ui-sref="properties.edit.images">Images</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.rates'}"><a ui-sref="properties.edit.rates">Rates</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.availability'}"><a ui-sref="properties.edit.availability">Availability</a></li>
</ul>
<ui-view></ui-view>

AngularJS - Show and Hide multiple content

In AngularJS, to simply show a field through an a tag, I would do in this way:
<div ng-show="aField">Content of aField</div>
<a ng-click="aField=true">Show aField</a>
until here, no problem.
I would like now to put more buttons and fields so that, when I click on A it shows the content of A, then when I click on button B, content of A disappears and content of B appears.
How can I do this? Thank you.
UPDATE
Thank you everyone for your solutions, they works! Now, I am doing a template for every content of and because I have much data to show but all in the same structure.
Here the index.html
<div ng-model="methods"
ng-include="'templateMethod.html'"
ng-repeat = "method in methods">
here the script.js:
function Ctrl($scope) {
$scope.methods =
[ { name: 'method1',
description: 'bla bla bla',
benefits: 'benefits of method1',
bestPractices : 'bestPractices',
example: 'example'},
{ name: 'method2',
description: 'bla bla bla',
benefits: 'benefits of method2',
bestPractices : 'bestPractices',
example: 'example'} ];
}
and here the templateMethod.html:
<table>
<tr>
<td>
<div ng-show="toShow=='{{method.name}}Field'">
<h3>{{mmethodethod.name}}</h3>
<p>
<strong>Description</strong>
{{method.description}}
</p>
<p>
<strong>Benefits</strong>
{{method.benefits}}
</p>
<p>
<strong>Best practices</strong>
{{method.bestPractices}}
</p>
<p>
<strong>Examples</strong>
{{method.example}}
</p>
</div>
</td>
<td class = "sidebar">
<ul>
<li><a ng-click="toShow='{{method.name}}Field'" class="{{method.name}} buttons">{{method.name}}</a></li>
</ul>
</td>
</tr>
</table>
It works!
But: if I click the first button and then the second one, the content of the first button do not disappear, it appears under the content of the first button...
Problem with the repetition?
Thanks
It might be better to handle more complex logic in the controller, but in general think about the content of the directive strings as normal js:
<div ng-show="aField">Content of aField</div>
<div ng-show="bField">Content of bField</div>
<a ng-click="aField=true; bField=false">Show aField</a>
<a ng-click="aField=false; bField=true">Show bField</a>
Or use ng-show in concert with ng-hide:
<div ng-show="aField">Content of aField</div>
<div ng-hide="aField">Content of bField</div>
<a ng-click="aField=true">Show aField</a>
<a ng-click="aField=false">Show bField</a>
In the former strategy, nothing shows upon page load. In the latter, the bField content shows by default. If you have more than two items, you might do something like:
<div ng-show="toShow=='aField'">Content of aField</div>
<div ng-show="toShow=='bField'">Content of bField</div>
<div ng-show="toShow=='cField'">Content of cField</div>
<a ng-click="toShow='aField'">Show aField</a>
<a ng-click="toShow='bField'">Show bField</a>
<a ng-click="toShow='cField'">Show cField</a>
I'm guessing that you have a list of items and want to show each item content. Something an accordion component does.
Here is a plunker that shows how you could do it: http://plnkr.co/edit/UTf3dEImiDReC89vULpX?p=preview
Or if you want to display the content on the same place (something like a master detail view) you can do it like this: http://plnkr.co/edit/68DJHL582oY4ecSiiUdE?p=preview
simply use one variable which content is visible. http://jsfiddle.net/gjbw7/
<a ng-click="show='a'">Show aField</a>
.
<div ng-show="show=='a'">Content of aField</div>
I would recommend to create a service in case your fields belong to different controllers.
Service:
App.factory('StateService', function() {
return {
openPanel: ''
};
});
Injecting the service in a Controller:
App.controller('OneCtrl', function($scope, StateService) {
$scope.stateService = StateService;
});
Finally using it a view:
<a ng-click="stateService.openPanel='home'">Home</a>
<div ng-show="stateService.openPanel == 'home'">Content of Home</div>
Demo: http://jsfiddle.net/codef0rmer/BZcdu/
Try this way.
<div>{{content}}</div>
<a ng-click="content='a'">Show aField</a>
<br>
<a ng-click="content='b'">Show bField</a>
<br>
<a ng-click="content='c'">Show cField</a>
<br>
<a ng-click="content='d'">Show dField</a>
<br>
<a ng-click="content='e'">Show eField</a>
<br>
<a ng-click="content='f'">Show fField</a>
Take a look at the ng-switch directive.
<div ng-switch="aField">
<div ng-switch-when="someValue1">
HTML content that will be shown when the aField variable value is equal to someValue1
</div>
<div ng-switch-when="someValue2">
HTML content that will be shown when the aField variable value is equal to someValue2
</div>
<div ng-switch-default>
This is where the default HTML content will go (if aField value is not equal to any of the ng-switch-when values)
</div>
</div>

Resources