How to assign dynamic value in angularJs Md Tab "ng-disabled"? - angularjs

I'm using angularjs md-tab there could be approx 10 tabs so I want to enable and disable those tags as per some situations, Here is the code snippet which I'm using :
In View
<md-tab label="{{video.name}}" ng-repeat="video in vm.videos" md-on-select="tabClicked()" ng-disabled="data.locked">
In Controller
$scope.data = {
selectedIndex: 1,
locked: true
};
now as you can see in md-tab "ng-disabled='data.locked'" by using controller "locked: true" it disabled all of the md-tabs.
What I want to do here is to enable 4 tabs and disable rest of the tabs.
What I'm planning to do here is to assign dynamic value under
ng-disabled="data.locked"
e.g.
ng-disabled="data.firstTab",
ng-disabled="data.secondTab" and so on and disable them in controller.
how can I do that and If there is any other way then please let me know.
Thanks

The example below demonstrates that each tab has its own locked setting.
angular.module('MyApp', ['ngMaterial']).controller('AppCtrl', function($scope) {
$scope.videos = [
{name: 'Video1', locked: true},
{name: 'Video2', locked: false},
{name: 'Video3', locked: true},
{name: 'Video4', locked: false}
];
});
<link rel="stylesheet" href="https://material.angularjs.org/latest/angular-material.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
<script src="https://material.angularjs.org/latest/angular-material.min.js"></script>
<div ng-controller="AppCtrl" ng-cloak="" ng-app="MyApp">
<md-tabs md-dynamic-height md-border-bottom>
<md-tab label="{{video.name}}" ng-repeat="video in videos" md-on-select="tabClicked()" id="tab" ng-disabled="video.locked">
</md-tabs>
</div>
Another way to do it is to have a function which will take the video object as parameter and decides if the corresponding tab is locked or not. The function should return true/false value and be used as:
ng-disabled="isLocked(video)"

Have an extra variable in videos array and based on that value you can disable it,
$scope.videos =[];
$scope.video = {};
/*your params*/
$scope.video.tabStatus = true;
$scope.videos.push($scope.video);
In view
<md-tab label="{{video.name}}" ng-repeat="video in vm.videos" md-on-select="tabClicked()" id="tab" ng-disabled="video.tabStatus">

in your view you are using this:
ng-disabled="data.locked"
This will be global to all tabs so you want individualize this. For this task you can use a function on the ng-disabled attribute and pass it your actual card:
ng-disabled="disabledCard(video)"
This will pass the actual video element and in the funcion you can handle if you want disable it or not.

Related

ui-bootstrap tab shows incorrect tab content when using ng-show

I have tabs, for which some are dynamically shown with ng-show. The problem is that if the first tab is not shown, then the second tab should be the active tab. But it is not working this way. It seems the first tab is still active, causing the tab 1 content to be in the tab 2.
What I need is the following, when the tabs are first loaded
In the code below if I set the active="1" for the ui-tabset, then it works as expected
<uib-tabset active="1">
But I can't do this, as this needs to be dynamic. The first tab may or may not be shown. I tried to use a binding value (as shown in the code below) for the active attribute, but that doesn't work. It still has the same result as the first image above.
I have the following MCVE (also Plunker)
html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.2.min.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body ng-app="exampleApp">
<div ng-controller="TabsDemoCtrl">
<uib-tabset active="initialActive">
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" ng-show="tab.show"
active="tab.active" index="$index">
{{tab.content}}
</uib-tab>
</uib-tabset>
</div>
</body>
</html>
script
angular.module('exampleApp', ['ui.bootstrap'])
.controller('TabsDemoCtrl', function($scope) {
$scope.tab1Show = false;
$scope.initialActive = $scope.tab1Show ? "0" : "1";
$scope.tabs = [
{ title: 'Tab 1', content: 'Tab 1 Content', active: false, show: $scope.tab1Show },
{ title: 'Tab 2', content: 'Tab 2 Content', active: true, show: true },
{ title: 'Tab 3', content: 'Tab 2 Content', active: false, show: false },
{ title: 'Tab 4', content: 'Tab 2 Content', active: false, show: true },
{ title: 'Tab 5', content: 'Tab 2 Content', active: false, show: true }
];
});
EDIT
There are typos in the content of the tabs, but it doesn't really affect the question and the results, as the question is really only concerned with the tab 2 content, which is correct.
use ng-if instead ng-show Plunker
<uib-tabset active="initialActive">
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" index="$index" ng-if='tab.show'>
{{tab.content}}
</uib-tab>
</uib-tabset>
Use ng-if instead of ng-show.
ng-show only hides other tabs(the ones before tab 2), while actually they are already rendered into the dom.
The first tab that gets rendered into the dom is the active one according to the implementation of ui-tabs. So, the first rendered li[tab item] is the active one and a css class active is applied to that- which creates the nice border for active state like below.
When you used ng-show, that item got created, got applied the active css class, and then it became hidden because of ng-show(which applied a css class on that element that does nothing but hides it by applying the rule display: none !important).
ng-if makes sure the element is not getting rendered into the dom, so the first element that gets rendered is tab 2 and there's no other elements before it, so logically- active class gets attached to it and you see the expected border and designs.

Angularjs One way Binding Binds Data Two Way

I have a pseudo code like this where using the one-way-binding operator(::) I tried to see if angular is watching for changes. So I had to include it inside an input tag. the model data inside the input tag should be resolved one way because of :: before it. However if I make changes to the input and click the button to see the changes it reflects the changes in the log. But it should not watch for the changes.
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular-animate.js"></script>
</head>
<body class="container" ng-controller="ItemsController">
<ul ng-repeat="item in ::items">
<li>
<!-- in actual code the input will not be included -->
<input type="text" ng-model="::item.name"> {{ ::item.name }}
<!-- actual code -->
<!-- {{ ::item.name }} -->
</li>
</ul>
<button type="btn" ng-click="click()">Button</button>
<script>
angular.module('app', [])
.controller('ItemsController', function ($scope) {
$scope.items = [
{name: 'item 1'},
{name: 'item 2'},
{name: 'item 3'}
];
$scope.click = function () {
for (var obj of $scope.items) {
console.log(obj.name);
}
};
})
</script>
</body>
</html>
A couple of things.
Is one time, no one way bonding. Is useful when you want an expression to be evaluated only once and not watching for changes.
The :: in ng-model is doing nothing, it will still update the scope with the value that you put and update the item name.
At the same time the {{ ::item.name}} should remain unchanged, because is one time binding and it won't watch for additional changes.
So you will see the changes in the log, because the value actually changes, what will not change is the view.

angular material design md-switch doesnt work within a tab

when placing a switch ( md-switch directive) within a tab, an aria error is thrown
ARIA: Attribute " aria-label ", required for accessibility, is missing on node: ​…​​
this happens regardless on whether an aria label is present or not. If the switch is moved outside of the tab, it works as expected.
plunker showing the issue
http://plnkr.co/edit/FmZAyLBpzhURbdZuuhQK?p=preview
<div ng-app="app" ng-controller="ctrl" >
<md-tabs md-selected="selectedIndex">
<md-tab id="tab1">Item One</md-tab>
</md-tabs>
<ng-switch on="selectedIndex" class="tabpanel-container">
<div role="tabpanel" id="tab1-content" ng-switch-when="0">
<div>
<md-switch aria-label="toggle" ng-model="data.switch">Switch : {{ toggle }}</md-switch>
</div>
</div>
</ng-switch>
</div>
<script>
var app = angular.module('app', ['ngMaterial']);
app.controller("ctrl", function ($scope) {
$scope.toggle = false;
$scope.selectedIndex = 0;
});
</script>
That was strange..
This issue seems to be fixed with the most current build of angular material (version 0.6.1-master-0767813).
Here's the plunker: http://plnkr.co/edit/chEaf9i50mIiThp0Jloq?p=preview
I just changed the scripts to the most current build:
<link rel="stylesheet" href="//rawgit.com/angular/bower-material/master/angular-material.css">
<script src="//rawgit.com/angular/bower-material/master/angular-material.min.js"></script>
Also you needed to change the ng-model to the toggle value. So instead of using
ng-model="data.switch"
You needed to use
ng-model="toggle"
pointing to $scope.toggle.

Get selected buttons of btn-group (buttons-checkbox) with angularjs

I'm using bootstrap and angular to build an application. In a HTML page, i'm using this:
<div class="btn-group-justified" data-toggle="buttons-checkbox">
<button type="button" class="btn fzbtn-consServices" ng-repeat="service in availability.services">{{service.name}}</button>
</div>
It's building a button group with dynamic values. Is there a practical way to obtain the selected buttons inside this button group?
I already tried some solutions, some of them are working but I don't know if it's the best way...
1: On "ng-click" method I would change a attribute value (eg. "checked" attribute) of each service to true or false;
2: I searched about any html attribute for btn-group which could offer me all the selected buttons inside this group, but i had no success;
3: I heard that i could beat this problem using Angular Filter, but i didn't find any similar example;
Anyone with a better idea? Thanks so much :)
This is the best solution I found until now:
<div class="btn-group-justified" data-toggle="buttons-checkbox">
<button type="button" class="btn fzbtn-consServices" ng-repeat="service in availability.services" ng-click="onClickService(service)" ng->{{service.name}}</button>
</div>
Controller:
$scope.onClickService = function (service) {
if (service.checked) {
service.checked = "false"
} else {
service.checked = "true";
}
}
Answer: Bootstrap UI
I feel your pain. Bootstrap is not always angular-friendly. But there is a good solution:
The easiest (and by far the cleanest) approach is to use Bootstrap UI. Built by the Angular Team, it is a rewrite of the javascript-portion of Bootstrap but for an Angular-friendly usage. Here's the section about buttons: http://angular-ui.github.io/bootstrap/#/buttons
Example solution: Checkbox button behavior
In this solution, the initial services array is used to store a boolean field 'selected' to know if any particular service is selected or not. (Similar to the "checked" in the question). This field is 2-way bounded to the checkbox state. Clicking the checkbox changes the field and changing the field changes the checkbox state.
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
var services = [
{ name:'Service A' },
{ name:'Service B', selected:true },
{ name:'Service C' },
{ name:'Service D', selected:true }
];
$scope.availability = { services:services };
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS BootStrap UI radios</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js"></script>
<script src="app.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-controller="MainCtrl">
<div class="btn-group-justified">
<label ng-repeat="service in availability.services" class="btn btn-primary" ng-model="service.selected" btn-checkbox>{{service.name}}</label>
</div>
<div ng-repeat="service in availability.services">{{service.name}} <span ng-show="service.selected">- selected</span></div>
</body>
</html>
Radio button behavior
I've included a solution for a "single selection" checkbox also known as a "radio-button". The "current selection" is bound to a variable on the scope. It will get updated automatically when the user picks an element. Setting it will, in turn, change the current selection.
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
var services = [
{ name:'Service A' },
{ name:'Service B' },
{ name:'Service C' },
{ name:'Service D' }
];
$scope.availability = { services:services };
$scope.model = {};
// Here we are using the service object instance as the "selection value".
// Depending on what you need, you could also use some sort of identifier or
// even the $index if that's more useful.
// Immediately select the second one.
$scope.model.selectedService = services[1];
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS BootStrap UI radios</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js"></script>
<script src="app.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-controller="MainCtrl">
<div class="btn-group-justified">
<label ng-repeat="service in availability.services" class="btn btn-primary" ng-model="model.selectedService" btn-radio="service">{{service.name}}</label>
</div>
<div>Current Selection is: {{model.selectedService.name}}</div>
</body>
</html>
NOTE: I used <label> instead of <button>, but I did not have your special CSS styles so it wasn't behaving on the screen, functionality-wise it works equally well with <button> elements.
You don't really specify why you are wanting to "get" the buttons. In general, getting a reference to DOM elements like this is not the "angular way." It is generally better to find a way to use angular's data-binding to manipulate UI elements.
For instance, if you want to show or hide buttons based on data or on another UI event, then use ng-show or ng-hide bound to a property of the service object you are binding these buttons to. Then you can update the object's property to change the UI. You should be able to find a similar way to make other changes (like setting classes, attributes, etc.) with angular's data-binding rather than doing it manually.

How to bind data using Angular in my case?

I am trying to create a tooltip based from from this post
Angular-UI-Bootstrap custom tooltip/popover with 2-way data-binding
I successfully created the popup but I have trouble delivering the content to my popover.html
I added this to my script.js
var app = angular.module('myApp', ['ui.bootstrap', 'ian.bootstrap']);
app.controller('myCtrl', function ($scope) {
$scope.item = {
title: 'Original Title',
content:'content 1' //newly added item
};
$scope.text = 'Click me';
});
and I want to display it in my popover.html
<div class="popover-content">
{{item.content}}
</div>
It doesn't show anything. Can someone help me about it? thanks a lot!
my plunker
http://plnkr.co/edit/5pBZ9qq79OPl2tGEeYYV?p=preview
Here is your updated working Plunkr
Basically you have to pass the attr iantooltip-content with the binding of the content item, not the raw text, and after in the directive pass in the directive isolate scope options the binding of the content like :
iantooltipContent: '='
Just change the appenToBody variable and you're done.
You should read the docs for more infos about Angular directive :)
You can add the ng-controller in your div and then specify the controller name like so :
<div class="popover-content" ng-controller='myCtrl'>
{{item.content}}
</div>
Before the use cases, the basic syntax to create a custom directive.
For all the code samples in this page I started from the angular-seed template.
Starting from the angular-seed skeleton is quite easy to extract a model to begin to implement custom directives.
<html ngApp="myApp">
...
<div my-first-directive></div>
<script src="lib/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/directives.js"></script>
...
</html>

Resources