Angularjs - data binding not working with controller - javascript

I am developing an app that uses bootstrap (v3.2.0) with angularjs (v1.2.26), I want to create a set of columns that are changable via a dropdown.
I have got the dropdown data binding ok, but I am failing to change the bootstrap responsive column classes when the user selects a different number of columns in the dropdown.
This fiddle shows my code so far.
The html...
<div data-ng-app="">
<div class="container-fluid">
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button> <span class="navbar-brand navbar-collapse-header">Header</span>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li data-ng-controller="ColumnController" id="columnDropDown" class="dropdown"> Columns: {{columnLayout.value}} <span class="caret"></span>
<ul class="dropdown-menu" role="menu">
<li data-ng-repeat="layout in columnLayouts"> <a data-ng-click="changeLayout(event)" href="#" class="portlet-column-number">{{layout.text}}</a>
</li>
</ul>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container-fluid -->
</nav>
</div>
<div class="row">
<div data-ng-controller="ColumnController" data-ng-class="getLayoutClass()">
<div class="panel panel-default">
<div class="panel-heading mo-product-header">Header 1</div>
<div class="panel-body">More content</div>
<div class="panel-footer">Layout class is {{getLayoutClass()}}</div>
</div>
</div>
<div data-ng-controller="ColumnController" data-ng-class="getLayoutClass()">
<div class="panel panel-default">
<div class="panel-heading mo-product-header">Header 2</div>
<div class="panel-body">Some other content</div>
<div class="panel-footer">Layout class is {{getLayoutClass()}}</div>
</div>
</div>
<div data-ng-controller="ColumnController" data-ng-class="getLayoutClass()">
<div class="panel panel-default">
<div class="panel-heading mo-product-header">Header 3</div>
<div class="panel-body">Some content</div>
<div class="panel-footer">Layout class is {{getLayoutClass()}}</div>
</div>
</div>
</div>
</div>
and js...
function ColumnController($scope) {
$scope.columnLayouts = [{
value: 3,
text: "Reset",
layoutClass: "col-sm-6 col-md-4"
}, {
value: 1,
text: "1",
layoutClass: "col-sm-12"
}, {
value: 2,
text: "2",
layoutClass: "col-sm-6"
}, {
value: 3,
text: "3",
layoutClass: "col-sm-4"
}];
$scope.changeLayout = function () {
$scope.columnLayout = this.layout;
}
$scope.getLayoutClass = function(){
return $scope.columnLayout.layoutClass;
}
$scope.columnLayout = $scope.columnLayouts[0];
}
UPDATE:
Ok so it turns out that I should have only added the 'ColumnController' to one element and in this case that element works best as the wrapper for all other elements.
However, I think to further improve this i will probably create a separate controller for navigation and then broadcast messages about change, in this case I could have the ColumnController listen for messages about column changes and repsond to them to change the model driving the column layout.

The problem is that you put too many data-ng-controller="ColumnController". You don't need to add it to every tag where you use angular binding {{}} or ngRepeat. You need only one on the wrapping container. For example:
<div data-ng-app="" data-ng-controller="ColumnController">
...
</div>
Demo: http://jsfiddle.net/pykm0tkv/25/

Related

Dynamically set class or id using index of ngFor loop

So I am trying to create a collapse (accordion) in Bootstrap 4 using Angular. I would love to be able to create almost the entire thing using an ngFor loop.
So far I have this:
<div class="row">
<div class="col-lg-6">
<div id="accordion" role="tablist" aria-multiselectable="true">
<div class="card" *ngFor="let environment of environments; let i = index;">
<div class="card-header" role="tab" id="headingi">
<h5 class="mb-0">
<a data-toggle="collapse" data-parent="#accordion" href="#collapsei" aria-expanded="false" aria-controls="collapsei">
Number: {{i}}
</a>
</h5>
</div>
<div id="collapseOne" class="collapse show" role="tabpanel" aria-labelledby="headingOne">
<div class="card-block">
<div *ngFor="let name of uniqueNames; let j = index" class="card infoBox">
<p>this is accordion {{i}}, section: {{j}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
What I am trying to do is use "let i = index" to set the id and class names needed to make the accordion know what to do when certain links are clicked. So ideally the first accordion section would have class and id of collapse0/heading0 and the next would have id and class of collapse1/heading1 etc.
However, the previous code must not be working because all the accordions and their headers show up and do nothing when clicked on. It does generate the correct number, show all the right headers, and the bodies associated with them.
Any help? thanks!
You can do it this way also
id="collapse{{i}}" class="heading{{i}}" attr.aria-controls="heading{{i}}"
and the fact that aria- attributes are being handled another way in angular you have to prefix them with attr.. In your example should that be attr.aria-controls="heading{{i}}".
You just have to databind id:
<div class="card-header" role="tab" [id]="'heading'+i">
<!-- and -->
<div [id]="'collapse' + i" class="collapse show" role="tabpanel" [aria-labelledby]="'heading' + i">
And then you can access your index via i.
*Here is working code with bootstrap 5 accordion with ngFor Angular 12 (dynamic id):
<div class="accordion" id="accordionPanelsStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header" id="panelsStayOpen-headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseOne" aria-expanded="true" aria-controls="panelsStayOpen-collapseOne">
Installed Offer Version Details
</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show" aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<ng-container *ngFor="let lineItem of allLineItems">
<!-- <line-item-detail [lineItem]="lineItem"></line-item-detail>-->
<div class="accordion-item my-4">
<h2 class="accordion-header" id="heading{{lineItem.id}}">
<button class="accordion-button" type="button" data-bs-toggle="collapse" attr.data-bs-target="#collapse{{lineItem.id}}" aria-expanded="true" attr.aria-controls="collapse{{lineItem.id}}">
{{lineItem.productType}} : {{lineItem?.productOffering?.name}}
</button>
</h2>
<div id="collapse{{lineItem.id}}" class="accordion-collapse collapse show" attr.aria-labelledby="heading{{lineItem.id}}">
<div class="accordion-body">
your body text
</div>
</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>
Even you can create sub-component of what is in ngFor like I commented the <line-item-detail></line-item-detail> tag.

Dynamically add or remove height and overflow-Y scroll property of a div using javascript

I have two sections [divs] on a page which is based on bootstrap. The left section contains a bootstrap panel which initially is resized to occupy the full page and then on clicking a glyph on the panel header, right section slides in sharing the page with the left panel. The contents of the right section are also panels whose contents are dynamic[table and dynamic rows]. The left panel is coded to always occupy window height. What I want is the right side div also to always occupy the window height and for overflow let a scroll appear for the right hand section. If I hard code the height of the right hand section and then give overflow-y: scroll, then it works. But I want to provide both using javascript and the height to be window width. Please help.
<body style = "height: 100%; overflow:hidden;">
<div id="navigationbar">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">TRAMM</a>
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav navbar-right" id="menu">
<li>Home</li>
<li>Page1</li>
<li>Page2</li>
<li>Page3</li>
<li>Page4</li>
</ul>
</div>
</div>
</nav>
</div>
<div id="wrapper">
<div id="main-wrapper" class="col-sm-6">
<div class="panel panel-info" style="margin-top: 1%">
<div class="panel-heading" id="JnName">
<div class="row">
<div class="col-sm-8">
NAME : Somename
</div>
<div class="col-sm-4" style="text-align: right;">
<span class="toggle-button bs-tooltip" id="ShowButton" style="cursor: pointer" data-toggle="tooltip" data-placement="left" title="Click to toggle sidebar">
<span id="glyphbutton" class="glyphicon glyphicon-backward"></span>
</span>
</div>
</div>
</div>
<div class="panel-body" id="SVGPanel">
</div>
</div>
</div>
<div id="sidebar-wrapper" class="col-sm-6 sidebar">
<div class="panel panel-info" style="margin-top: 1%;" id="JunctionParam">
<div class="panel-heading" id="JunctionParameters">Junction Parameters</div>
<div class="panel-body">
<p>
Please fill the content which is more than the window height here...
</p>
</div>
</div>
</div>
</div>
</body>
And I have tried this. But it does not seem to be working
function autoAdjust()
{
var $sidebarwrapperscroller;
$sidebarwrapperscroller = document.getElementById('sidebar-wrapper');
$sidebarwrapperscroller.style.height = $(window).height();
alert("setheight");
$sidebarwrapperscroller.style.overflowY = "scroll";
}
But without any javascript, if I set
<div id="sidebar-wrapper" class="col-sm-6 sidebar" style="height: 700px; overflow-y:scroll;">
Then its working. But I want the height to be set to window height dynamically.
If I understood you you need to add overflow-y:scroll and height:auto to sidebar-wrapper ?
Maybe with jquery?
$("#sidebar-wrapper").click(function() {
if ( $("#sidebar-wrapper").css('display') == 'visible' ){
$("#sidebar-wrapper").css({"height":"auto", "overflow-y":"scroll"});
}else{
$("#sidebar-wrapper").css({"height":"", "overflow-y":""});
}
});
Replace sidebar-wrapper id with your glyph id in .click function
JSFiddle

Bootstrap3: How to use two off-canvas sidebars?

I have this template that initially shows:
Sidebar1 - Content - Sidebar2
But when the user is in mobile view, I need to disappear the two sidebars and that this can be opened by a button, one at a time...
Button1 - opens sidebar1 to the right.
Button2 - opens sidebar2 to the left.
Anyone know if this is possible or has it done?
Code
<div class="container">
<div class="row row-offcanvas row-offcanvas-right">
<div class="col-xs-2 col-sm-3 sidebar-offcanvas" id="sidebar" role="navigation">
<div class="list-group">
Link
Link
Link
Link
Link
Link
</div>
</div><!--/span-->
<div class="col-xs-12 col-sm-6">
<p class="pull-left visible-xs">
<button type="button" class="btn btn-primary btn-xs" data-toggle="offcanvas1">
Filters <i class="fa fa-arrow-right"></i>
</button>
</p>
<p class="pull-right visible-xs">
<button type="button" class="btn btn-primary btn-xs" data-toggle="offcanvas">
<i class="fa fa-arrow-left"></i>
Details</button>
</p>
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>This is an example to show the potential of an offcanvas layout pattern in Bootstrap. Try some responsive-range viewport sizes to see it in action.</p>
</div>
</div><!--/span-->
<div class="col-xs-3 col-sm-3 sidebar-offcanvas" id="sidebar" role="navigation">
<div class="list-group">
Link
Link
Link
Link
Link
Link
</div>
</div><!--/span-->
</div><!--/row-->
</div>
Javascript
$('[data-toggle=offcanvas]').click(function () {
$('.row-offcanvas').toggleClass('active');
});
$('[data-toggle=offcanvas1]').click(function () {
$('.row-offcanvas').toggleClass('active');
});
Let's give this a try... I added a new row at the bottom of your current HTML to represent the same exact links that are displayed on the edges but are hidden until a button is toggled. Let's take a look at the HTML first:
HTML
<div class="row">
<div class="col-xs-3 col-sm-3 sidebar-offcanvas hide trial2" id="sidebar" role="navigation">
<div class="list-group"> Link
Link
Link
Link
Link
Link
</div>
</div>
<div class="col-xs-3 col-sm-3 sidebar-offcanvas pull-right hide trial " id="sidebar" role="navigation">
<div class="list-group"> Link
Link
Link
Link
Link
Link
</div>
</div>
</div>
As you can see, I copy and pasted the exact same HTML and added the following classes: hide, trial, trial2
Class hide: This is a built in BootStrap class that hides all content within the specified tag. I toggle this class with jQuery later on.
Class trial/trial2 : This is just a random name I chose to make sure the toggle effect was going to work, you can virtually name it whatever you want, but just make sure you reference the tag.
Let's look at the new jQuery:
jQuery
$('[data-toggle=offcanvas]').click(function () {
$('.trial2').toggleClass('hide');
});
$('[data-toggle=offcanvas1]').click(function () {
$('.trial').toggleClass('hide');
});
It's virtually the same code you had but I have it now toggling the hidden content.
Conclusion:
I added a few other things as well - such as the ability to hide the two side-navigation bars as the screen shrinks to a smaller size. Just take a look at the code I will provide via a JSFiddle and you will understand it a bit better.
DEMO JSFiddle
I fixed like this:
HTML
<div class="row-fluid row-offcanvas row-offcanvas-left">
<div class="row-fluid row-offcanvas row-offcanvas-right">
<div id="filters"></div>
<div id="content">
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<ul class="nav navbar-nav nav-pills">
<li class="visible-xs"><a> <span class="glyphicon glyphicon-filter" data-toggle="offcanvas" data-target=".sidebar-nav"></span> </a></li>
<li class="visible-xs"><a> <span class="glyphicon glyphicon-list-alt" data-toggle="offcanvas1" data-target=".sidebar-nav"></span> </a></li>
</ul>
</div>
</nav>
</div>
<div id="detail"></div>
</div>
JAVASCRIPT
$('[data-toggle=offcanvas]').click(function() {
$('.row-offcanvas-left').toggleClass('active');
});
$('[data-toggle=offcanvasa]').click(function() {
$('.row-offcanvas-right').toggleClass('active');
});

Anchoring to the same page [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I wanted to point to a portion in the same page. So used the anchor method. But the problem is, I have a static navigational bar at the top. So the heading of the section goes below the menu bar since the anchor is set to the heading. The menu bar is of 100px height. I was wondering if there is any way we can show this heading too?
If you want more details, just let me know.
<!---NAVIGATION BAR SECTION------>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<a class="navbar-brand" href="index.html"><img id="logo" src="img/logo.png"></a>
<button class="navbar-toggle" data-toggle="collapse" data-target=".navHeaderCollapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="collapse navbar-collapse navHeaderCollapse">
<ul class="nav navbar-nav navbar-left">
</ul>
<ul class="nav navbar-nav navbar-right">
<li>FEATURES</li>
<li>PRICING</li>
<li id="scroll2" class="navLog">LOGIN</li>
<li id="scroll3" class="navLog">SIGN UP FREE</li>
</ul>
</div>
</div>
</div>
<!---NAVIGATION BAR ENDS------>
This is the nav section from which I wanted to move to other portions
<div class="jumbotron action-block-green ">
<div class="container text-center">
<div class="row">
<div class="col-sm-8">
<ul class="nav navbar-nav navbar-left">
<li>TECHNOLOGY</li>
<li>SCREENSHOTS</li>
<li>FEATURES</li>
</ul>
</div>
<div class="col-sm-4">
</div>
</div>
</div>
</div>
I anchored the first link (technology) to here
<div class="jumbotron sectionBlock white ">
<div class="container text-center">
<h2 id="technology" style="color:#202020;margin-top: 0px;">Cutting-Edge Technology</h2>
<h3>Accurate, Reliable, Scalable and Hi Performace</h3>
<p style="margin:10px 0">blabhfufwehuf wiuefh wiu hfiuw fiuw fiuwhe fiwu hfiwue fhiwuh f</p>
<div class="row" style="margin-top:20px;">
<div class="col-md-4">
<div class="certified-uptime"></div>
</div>
<div class="col-md-4">
<div class="multiple-datacenters"></div>
</div>
<div class="col-md-4">
<div class="hosteb-by"></div>
</div>
</div>
</div>
</div>
I would do the scrolling using jQuery and changing the anchors in the URL to elements that don't exist on the DOM with the same value for id or name. (so that the scroll is not done automatically)
Living demo
$(window).on('hashchange',function(){
//you can see it manually or calculate it using jQuery by using $.height();
var header = 60;
//Getting the anchor and replacing the underscore
var value = window.location.hash.replace('_', '');
//getting our destination
var dest = $(value).position();
//if the element exist on the DOM
if(typeof dest !== "undefined"){
var dtop = dest.top;
//proceeding to scroll
$('html, body').animate({
scrollTop: dtop - header
}, 1000);
}
});
The links in my example look like #_link1 and the id needed to appear in the DOM should be like id="link1:
<div id="menu">
Link 1
Link 2
Link 3
</div>
...
<h1 id="link1>Link 1</h1>
Of course, you can change the underscore (_) on the URL for any other character or symbol you want. Just make sure to replace it for an empty string on the replace statement of the code I provided.

Collapse nested accordion groups based on custom class

I'm using Twitter Bootstrap 2.3.2 with Asp.net MVC.
I have a set of nested accordions on a tab pane and other accordions on other tab panes.
The External accordions are in an accordion-group and the Internal accordions are in another group, nested inside each External accordion.
The colours are applied using CSS rules on custom classes.
.accordion-toggle.outcome {
background-color:#d9edf7;
}
.accordion-toggle.outcome.collapsed {
background-color:White;
}
.accordion-toggle.achievement {
background-color:#dff0d8;
}
.accordion-toggle.achievement.collapsed {
background-color:White;
}
I need to force the full collapse of the open accordions depending on which new accordion is selected. If an internal accordion is selected then I only want the other internal accordions to close. If an external accordion is selected I want the internal and external accordions to close.
Closing means assigning the 'collapsed' class to the accordion-toggle, which determines the highlight colour of the accordion-heading.
I have the following javascript which needs amending to select the different levels of accordion. The class of 'outcome' for External and 'achievement' for internal are currently the only difference between the two.
I've tried a variety of if/else combinations but none of them seem to work. I've included the javascript I use when changing tabs as this might change how I need to approach this.
<script type="text/javascript">
//need to collapse all when tab changes
$('a[data-toggle="tab"]').on('shown', function (e) {
$('.accordion').find('.accordion-toggle').addClass('collapsed');
$('.accordion').find('.accordion-body').removeClass('in');
$('.accordion').find('.accordion-body').height('0px');
}
);
//collapse accordion depending on class
// from https://github.com/twbs/bootstrap/issues/7213#issuecomment-18547519
$('.collapse').on('hide', function () {
//do something to select internal or external accordion here...
$('[href="#' + $(this).attr('id') + '"]').addClass('collapsed');
});
</script>
The HTML for the above accordion set is as follows:
<div class="accordion" id="interventions">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle outcome collapsed" data-toggle="collapse" data-parent="#interventions" href="#collapse12">
<label for="">Test Finance</label>
</a>
</div>
<div id="collapse12" class="accordion-body collapse">
<div class="accordion" id="intervention0">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention0" href="#collapse012">
<label for="">Achievement Finance 3</label>
</a>
</div>
<div id="collapse012" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention0" href="#collapse111">
<label for="">Achievement Finance 2</label>
</a>
</div>
<div id="collapse111" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle outcome collapsed" data-toggle="collapse" data-parent="#interventions" href="#collapse10">
<label for="">Huge Money</label>
</a>
</div>
<div id="collapse10" class="accordion-body collapse">
<div class="accordion" id="intervention1">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention1" href="#collapse010">
<label for="">Achievement Finance 1</label>
</a>
</div>
<div id="collapse010" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I managed to sort this out using the following javascript. The custom classes are only used by the CSS to apply the correct colour to an accordion-toggle when it is open or collapsed.
The css is amended to:
.accordion-toggle.outcome {
background-color:#d9edf7;
}
.accordion-toggle.achievement {
background-color:#dff0d8;
}
.accordion-toggle.collapsed {
background-color:transparent;
}
Thanks to Ammu for helping with this related question.
Javascript
//function to collapse all accordions when changing tabs
function tabCollapse() {
$('.accordion').find('.accordion-toggle').addClass('collapsed');
$('.accordion').find('.accordion-body').removeClass('in');
$('.accordion').find('.accordion-body').height('0px');
}
//function to fully collapse accordion on same page
function pageCollapse(inner) {
$('#' + inner).find('.accordion-toggle').addClass('collapsed');
$('#' + inner).find('.accordion-body').removeClass('in');
$('#' + inner).find('.accordion-body').height('0px');
}
//collapse all when tab changes
$('a[data-toggle="tab"]').on('shown', function () {
tabCollapse();
});
//collapse inner accordion on same page
$('.accordion').on('hidden', function (e) {
var inner = e.target.id;
pageCollapse(inner);
});
//on hide remove colour
$('.accordion').on('hide', function (e) {
var selected = e.target.id;
$('#' + selected).siblings().find('.accordion-toggle').addClass('collapsed');
});

Categories