Angular Material's md-checkbox - all checkboxes check when using ng-model. - angularjs

The radio choice, styled as a checkbox, works great like this with no issues:
<div ng-repeat="choice in regions| orderBy: 'description'">
<input type="radio"
value="{{choice.name}}"
name="regionRadio"
ng-model="radio.region">
{{choice.description}}
</div>
input[type="radio"] {
-webkit-appearance: checkbox;
-moz-appearance: checkbox;
-ms-appearance: checkbox;
}
However, if I want to use Angular Materials md-checkbox:
<div ng-repeat="choice in regions| orderBy: 'description'">
<md-checkbox type="radio"
value="{{choice.name}}"
ng-model="radio.region">
{{choice.description}}
</md-checkbox>
</div>
It does not handle the ng-model well. When just one checkbox is selected, all the checkboxes become selected(checked).
Any suggestions how to make md-checkbox work in the same manner with ng-model as before?

Your question is a bit confusing. md-checkbox does not have the attribute type according to the docs. You should really use md-radio-group to stay within AM best practice.
I have created an example with md-checkbox and md-radio-group - CodePen
Clicking a checkbox does not select all the checkboxes but you can select more than one checkbox. It's quite easy to write some code to make the checkboxes act like radio buttons though.
Markup
<div ng-controller="AppCtrl" ng-cloak="" ng-app="MyApp">
<p>Checkbox</p>
<div ng-repeat="choice in regions| orderBy: 'description'">
<md-checkbox type="radio"
value="{{choice.name}}"
ng-model="radio.region">
{{choice.description}}
</md-checkbox>
</div>
<p>{{radio.region}}</p>
<p>Radio Group</p>
<md-radio-group ng-model="newradio.region">
<md-radio-button ng-repeat="choice in regions| orderBy: 'description'" value="{{choice.name}}" class="md-primary">{{choice.description}}</md-radio-button>
</md-radio-group>
<p>{{newradio.region}}</p>
</div>
JS
angular.module('MyApp',['ngMaterial'])
.controller('AppCtrl', function($scope) {
$scope.regions = [
{name: "sky", description: "The sky"},
{name: "sea", description: "The sea"},
{name: "land", description: "The land"},
{name: "water", description: "The water"}
];
});

I'll take a shot in the dark and assume you had the same (or very similar) issue as me. I was stunned to search and find this issue was unique to you and me until I started to look into my parent containers and realized my mistake.
My issue was that I included my md-checkbox INSIDE an md-list-item. Upon clicking anywhere in that md-list-item, my md-checkbox toggled. In retrospect, I should have noticed sooner with the giveaway ripple effect.
The md-checkbox directive is one of the proxied elements that gets triggered when clicking inside an md-list-item. Adding the class "md-no-proxy" to the md-list-item element removes this (and the ripple) effect.*
If you were not using a parent md-list-item element, I suggest looking into whether or not any of your parent containers/directives proxies an ng-click in it's children elements.
*Source:
https://material.angularjs.org/latest/api/directive/mdListItem

Related

AngularJS Bootstrap UI Typeahead Not Working Properly with Custom Popup Template

I'm working on a .NET MVC application that has some AngularJS pages in it. I'm trying to use Bootstrap UI Typeahead but it's not quite working properly.
If I start to type in the textbox the autocomplete popup opens with potential matches:
However, if I click on one of the matches nothing happens and the underlying angular model is not updated:
The really strange thing is that if I hit tab while the popup is open the first match will get selected and the angular model is updated appropriately:
This is the template I'm using:
<script type="text/ng-template" id="customTemplate.html">
<div class="search-result search-result--mos ng-scope" ng-if="matches.length > 0">
<ul>
<li ng-repeat="match in matches track by $index" class="search-result__item ng-scope uib-typeahead-match">
<div uib-typeahead-match match="match" index="$index" query="query" ng-bind-html="match.model.value"></div>
</li>
</ul>
</div>
This is the relevant front-end code:
<section class="mos intro" data-ng-controller="MosConverterController as vm">
<div>
<form ng-submit="GetCareers()" class="form form--mos">
<div class="form__row">
<div class="form__col form__col--half-plus">
<label for="MOS" class="form__label">MOS/Rate/Duty Title</label>
<input type="text" ng-model="vm.model.SearchTerm" uib-typeahead="career.value for career in vm.model.CareerResults | filter:$viewValue | limitTo:8" typeahead-popup-template-url="customTemplate.html" id="MOS" class="form__input--text" placeholder="Start Typing" name="MOS" required>
<div>Current Search Term: {{vm.model.SearchTerm}}</div>
<textarea>{{vm.model.CareerResults}}</textarea>
</div>
</div>
</form>
</div>
Here's our angular model. Note that we're using Typescript in this project:
import {MosConverterSearchResult} from "../models";
export class MosConverterModel implements Object {
SearchTerm: string = null;
CareerResults: MosConverterSearchResult[];
SelectedCareer: MosConverterSearchResult;
}
I followed the tutorial from the Angular Bootstrap documentation here for the "Custom popup templates for typeahead's dropdown" section but I can't figure out what I'm doing wrong. I'm sure it's something simple but I just can't figure it out. I should note that adding ng-click to the li element like they have in the tutorial doesn't fix the issue. I've tried it like this before:
<li ng-repeat="match in matches track by $index" class="search-result__item ng-scope uib-typeahead-match" ng-click="selectMatch($index)">
<div uib-typeahead-match match="match" index="$index" query="query" ng-bind-html="match.model.value"></div>
</li>
After banging my head against my desk for a couple of hours I figured out the issue was the ng-if in my template. The example in the tutorial link I posted above uses ng-show. ng-if destroys the DOM element and destroys its scope in the process. That's why nothing would happen when I clicked on an item from the list. Not sure why the tabbing would work though if this was indeed the case. If anyone knows please add a comment or better answer.

mdChips with filter

I'm a Newbie to AngularJS trying something with Angular Material and need some ideas / help.
I have icons of Font Awesome which are displayed with ng-repeat:
<ul ng-repeat="item in items">
<i ng-class="{'test': item.active}" class="fa fa-{{item.name}}">{{item.name}}</i>
</ul>
Below I have a list of the icons a with checkboxes:
<span ng-repeat="item in items | filter: item.active = false">
<input type="checkbox" ng-model="item.active"> {{item.name}}<br>
</span>
If a checkbox is activated, the list entry should disappear from the list.
This works with the filter of the property item.active
Now I want to display the activated items above the list with md-chips (Angular Material Chips).
So if a list item is activated, the element should be a md chip above the list (not displayed in the list anymore).
If I click on the 'X' in md-chip, only the state of the property item.active should change again to false.
I have my working files on Plunker, so my current working state can be read:
https://plnkr.co/edit/t3Xpp2AKEJHXBWhkLUYZ?p=preview
Does anybody got an idea how can I implement this?
The easiest way to do that is apply ng-click to your md-chip item and by this click it will set active = false:
...
<md-chips class="custom-chips" ng-model="items | filter: {active:true}" readonly="true">
<md-chip-template>
<span ng-click="$chip.active=false">
<strong>{{$chip.name}}</strong>
</span>
</md-chip-template>
</md-chips>
...
Here is a plnkr example.
EDIT:
Modified plunker to show only active md-chips.
Hope it will help.
You may want to filter the chips array using the builtin filterFilter function. The watcher that contains the latter will invoke the listener whenever the filterText changes.
...
$scope.array = [
"active directory",
"outlook",
"edrm",
"gcdocs",
"novell",
"iPrint",
"iManager",
"sigma",
"bitlocker",
];
$scope.filterText = "";
$scope.$watch('filterText', function(newValue, oldValue) {
$scope.filteredArray = filterFilter($scope.array, $scope.filterText);
}, false);
...
The following markup will render and filter the chipset.
<md-content flex class="md-padding">
<label>Filter: <input ng-model="searchText"></label>
<md-chips ng-model="filteredArray" readonly="ctrl.readonly"
md-removable="removable" placeholder="Enter an issue...">
<md-chip-template>
<strong>{{$chip}}</strong>
</md-chip-template>
</md-chips>
</md-content>
For further information on filters please see https://docs.angularjs.org/guide/filter
For further information on $watch please see https://docs.angularjs.org/api/ng/type/$rootScope.Scope

Angular Select Tag with Bootstrap Dropdown Styling

I need to create custom styling for a select dropdown (including the options). The more I've dug into this, the more I've realized that styling options is quite difficult.
I'm currently using Bootstrap's dropdown and it works great, except for the fact that I have to use a function to assign a value.
This is how I am currently using a 'custom select dropdown':
<div class="form-element-container">
<div class="drop-down dropdown-toggle">
<label for="chooseAdvisor"></label>
<div>
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">{{mySelection}}</button>
<ul class="dropdown-menu">
<li ng-repeat="option in options">{{option}}</li>
</ul>
</div>
</div>
</div>
You can see that on click, I have to manually set the option in my controller rather than it being directly bound to my model. Is there any way that I can use Bootstrap's dropdown styling with angular's select tag?
I would love to be able to use my options repeater with 'track by', etc:
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
You can try it:
https://angular-ui.github.io/bootstrap/#/dropdown
Just a suggestion, I've not tested it yet.
Update answer:
I think you can instead of angular module : acute-select
https://github.com/john-oc/acute-select
Demo : http://john-oc.github.io/

ng-click and ng-model not working in a popover

I have an ng-click in in a bootstrap popover that doesnt seem to work. when I move it out of the popup into the page it seems to work. Also the ng-model value doesnt seem to update either.
<div id="popover-content" class="hide">
<input type="text" placeholder="Quote ID" ng-model="selectedItems.quote.label">
<button type="button" ng-click="newQuote()">New quote</button>
</div>
Is this because the popover is created in the dom and angular does not know it exists? Any ideas how I can get it to work? Thanks
EDIT:
Here is the newQuote
$scope.newQuote = function() {
$scope.selectedItems.quote = angular.copy(defaultQuote);
$scope.solution.quotes.push($scope.selectedItems.quote);
$scope.selectedItems.quote.label = 'New Quote';
$scope.addMessage('Quote created successfully', 2);
};
EDIT 2
Here is a plunker showing the issue - the alert is not displayed when ng-click="newQuote()" is fired
http://plnkr.co/edit/ANH98vlflPK9c5qA3ohO?p=preview
You should create a Directive to make angular works with Bootstrap Popover. You can take a look in your Developer console when using Bootstrap Popover. It actually does not reuse the DOM that you predefined - ie :
<input type="text" placeholder="Quote ID" ng-model="selectedItems.quote.label">
<button type="button" ng-click="newQuote()">New quote</button>
But add in a new piece of DOM - ie
<div class="popover fade bottom in" role="tooltip" id="popover770410" style="top: 30px; left: 0px; display: block;">
<div class="arrow" style="left: 15.9420289855072%;">
</div><h3 class="popover-title">New quote</h3><div class="popover-content">
<input type="text" placeholder="Quote ID" ng-model="selectedItems.quote.label" class="ng-pristine ng-untouched ng-valid">
<button type="button" ng-click="newQuote()">New quote</button>
</div>
</div>
Therefore Angular will not understand new piece of DOM because it has not compiled yet - ie : You cannot use ng-click as well as ng-modal. One way to work around this is to create a directive and compile your html content before passing that piece of DOM to Bootstrap Popover.
I have created this fiddle to demonstrate this idea.
As you can see :
I have compile you content and bind it to current scope
$compile(content)(scope);
Before passing that piece of DOM to popover
var options = {
content: compileContent,
html: true,
title: title
};
$(elem).popover(options);
With this way to can let Angular understand new piece of DOM added and do its work correspondingly.
Furthermore, actually there quite some directives that works with Bootstrap Popover that you can take a look at instead of creating new directives
AgularUI Bootstrap
Angular Strap
Reference :
http://tech.pro/tutorial/1360/bootstrap-popover-using-angularjs-compile-service
twitter bootstrap popover doesn't work with angularjs

ng-click showing all the hidden text field on ng-repeat rather than one in Angular

I started to work with Angular, it's pretty good to implement, I stuck with a single issue at ng-click
I am getting data dynamically and showing with ng-repeat, and I want to update the data at pencil click and for it I am using input text element, but when I click on pencil It's opening all the text fields
Here is my HTML code
<
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" data-ng-hide="hideCatButton">{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" data-ng-model="item.category_name" data-ng-show="hideField">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" data-ng-show="hideOkButton">Done</span>
<div class="pull-right">
</div>
</div>
</div>
And here I Angular code
$scope.updateCategory=function(category_id,updated_cat_name, $index){
Category.updateCat($rootScope,$scope,$index,$http,$timeout,updated_cat_name,old_cat_name,category_id);
};
$scope.updatePen=function($index){
old_cat_name=$scope.scroller.items[$index].category_name
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
};
I created a Category service to perform task like update
I didn't get any proper solution yet.
Can anybody help me?
Thank You.
If you only want to hide/show one of the elements in the list you need to specify that in some fashion. Right now you have a three rootScope booleans:
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
being set for the entire list, and you need to set a show properties on each individual in the list.
In your controller function you can do something like this before you expect a click:
//normal for loop so that you have the index
for(var i=0; i < $scope.scroller.items.length; i++){
$scope.scroller.items[i].show = false;
}
Then you can do something like this to actually show the fields:
HTML:
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" ng-hide="!item.show">
{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" ng-model="item.category_name" ng-hide="!item.show">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" ng-show="item.show">Done</span>
<div class="pull-right">
</div>
</div>
</div>
Controller:
//controller declaration --
$scope.updatePen = function(index){
$scope.scroller.items[index].show = true;
};
It's my understanding that you need all three properties to show once a click happens, so I condensed all the show properties into one single show property.
Your view only sees that hideField is true and performs that action for all of the items in your array. I hope this helps!

Resources