Angular ng-show (or ng-if) not updating on value change - ng-show

I have a simple example at plunker. I have an ng-show on one element and a select as another element. The select should toggle showing/hiding the other (input) element. Initially setting the select to Yes shows the other input element as expected. Then setting the select to No does toggle the scope value to false as expected, but does not hide the input element.
I've scoured the other posts related to this and the ones I found are around having or not having {{}} on the ng-show (I don't as it should be) or not having the value on $scope (which I do). I thought is may be a $scope.apply() issue, but then why does the 1st change to Yes work? Also adding the apply still does not make the No(false) work. What am I missing?
TIA!
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.conf = {};
});

You need to check ng-show="conf.is_ieee=='true'" instead of ng-show="conf.is_ieee". Check this plunker.
<div class="col-md-4" ng-show="conf.is_ieee=='true'">
<label class="form-label">IEEE Conference ID:</label>
<input type="text" class="form-control" name="ieee-id" ng-model="conf.ieee_id"/>
</div>
http://plnkr.co/edit/MXvuhSPB0ChJyDrvPI55?p=preview

Related

How to add header to the ngbtypeahead window?

I am trying to implement typeahead functionality in Angular. I am using ngbTypeahead from ng-bootstrap for this as shown below.
<input id="typeahead-template" type="text" class="form-control form-rounded" [ngbTypeahead]="search" [resultTemplate]="rt" [inputFormatter]="formatter" />
<ng-template #rt let-r="result" let-t="term">
<img [src]="'https://upload.wikimedia.org/wikipedia/commons/thumb/'+r['flag']" class="mr-1" style="width: 16px">
<ngb-highlight [result]="r.name" [term]="t"></ngb-highlight>
</ng-template>
This is displaying result like
result1
result2
result3
but I want a header to be added and the result should be in the format
The results are
result1
result2
result3
Can someone please help with this?
This isn't supported by ng-bootstrap's Typeahead component, however you can use CSS to insert text before the results. The only problem with this solution is that you need to use ::ng-deep which is deprecated and likely to be dropped by Angular soon.
Add this to your component's CSS:
::ng-deep ngb-typeahead-window:before {
content: "The results are:";
}
and you should see the following when results are displayed:
This will prepend the typeahead results with the text specified as the value of the content property.
Please see this StackBlitz for a demo
There is a hack I have been using:
Use the first row as a dummy row with a specific attribute
Track the existence of that attribute to render the header at the template
Use CSS to make the first row unselectable.
.popup-custom-class .dropdown-item:first-of-type {
pointer-events: none;
}

Displaying Play/Pause Button in angular

I want to implement the show/hide feature of the play and pause buttons on a list of tracks in angular 7. I originally got this feature partially working using angular animation, but my method would change the state of all buttons in my list instead of a single item. I've also tried using ngClass but couldn't seem to get it working right.
Below is my latest efforts. Please help me.
<mat-card class="track-box" *ngFor="let track of tracks" cdkDrag>
<div class="custom-placeholder" *cdkDragPlaceholder></div>
<span>
<mat-icon
class="play-button md-48"
[ngClass]="{'show' : track === selectedTrack}"
(click)="toggle(track)"
> play_circle_outline</mat-icon>
<mat-icon
class="pause-button md-48"
[class.selected2]="track === selectedTrack"
(click)="toggle(track)"
>pause_circle_outline</mat-icon>
</span>
I would have to disagree with #Tomato 's answer, as per my comment on his answer.
However, what I would recommend is using Angular's NgClass which is similar to ngIf. But here's the catch.
When it comes to ngIf, you're creating 2 components, hiding one and showing the other, and doing that operation over and over again. Which is not the best code practice.
However, in the case of ngClass, you're creating one component and 2 separate SCSS classes for the same component. Whenever a certain condition is satisfied, one SCSS Class gets applied, and so forth.
HTML File
<span>
<button
class="play-pause-button"
[ngClass]="toggle(track)"></button>
</span>
TS File
export class Component {
let isPlay = false;
public toggle(track: string) {
this.isPlay = !this.isPlay;
this.isPlay ? return 'play-button'; : return 'pause-button'
}
}
That way, the toggle() function will return a SCSS class name based on the current status of the button itself.
Using ngClass
You could change the shown button icon by using ngClass as following:
<mat-card class="track-box" *ngFor="let track of tracks" cdkDrag>
<div class="custom-placeholder" *cdkDragPlaceholder></div>
<span>
<mat-icon
class="md-48"
[ngClass]="{'play-button' : track != selectedTrack,
'pause-button' : track === selectedTrack}"
(click)="toggle(track)">Some output here</mat-icon>
</span>
</mat-card>
Using ngIf
You could maybe use an ngIf (docs) to show/hide the buttons, though as Chris pointed out, this creates two elements for every track in your list and could cause performance issues on a very huge list.
<mat-card class="track-box" *ngFor="let track of tracks" cdkDrag>
<div class="custom-placeholder" *cdkDragPlaceholder></div>
<span>
<mat-icon
class="play-button md-48"
*ngIf="track != selectedTrack"
(click)="toggle(track)">play_circle_outline</mat-icon>
<mat-icon
class="pause-button md-48"
*ngIf="track === selectedTrack"
(click)="toggle(track)">pause_circle_outline</mat-icon>
</span>
</mat-card>
When your selectedTrack does not equal the track, show the play-button, if it is the same track, show the pause-button.
You could also use the if-else-block for this (from the docs):
<div *ngIf="condition; else elseBlock">Content to render when condition is true.</div>
<ng-template #elseBlock>Content to render when condition is false.</ng-template>

Webdriver.io how to select and element that changes based on the number of like elements on the page

I want a way to select the udp-address-input field inside of this named-source-add div. The problem I'm having is udp-address-input-<+id> element has a different number based on how many named sources have been added. There is always only 1 udp-address-input-<+id> inside of the named-source-add div so I was wondering if I can limit my search inside that div?
<div id="named-source-add" class="named-div">
<input type="text" class="table-cell" data-bind="textInput: address, attr:
{id: 'udp-address-input-'+id, readonly: readonly, required: role() ==
'destination'}" id="udp-address-input-18">
</div>
I used xpath, only looking for inputs with ids starting with udp-address-input inside of the named-source-add div.
//div[#id='named-source-add']//input[contains(#id,'udp-address-input')]
And I had to add slashes to get this to work with my javascript webdriverio pageobject like this:
udpMulticastAddr:{ get() { return '//div[#id=\'named-source-add\']//input[contains(#id,\'udp-address-input\')]';}},

Keep classes assigned with Angular when changing the state

HTML:
<div class="col-xs-4" ng-repeat="product in products" ng-click="selectItem($event)"> {{desc(product)}}</div>
In controller:
$scope.selectItem = function (event) {
$(event.target).addClass('greenLetter');
}
This works, the problem is when I need change state, if I go back to this controller, I miss greenLetter, how can I keep it?
The Angular way to do that would be using ngClass.
In the following code, clicking the element will set selected to the current product you are repeating over (using $index).
ngClass will be applied only if the selected element is the clicked one.
<div class="col-xs-4"
ng-class="{'greenLetter': selected == $index}"
ng-repeat="product in products"
ng-click="selectItem($index)">
$scope.selectItem = function(index) {
$scope.selected = index;
}

Bootstrap DatePicker style not working properly angularjs

Can someone help me look at this plunkr. The style seems not to be working.
<!DOCTYPE html>
<div ng-controller="testController">
<h1>Hello Plunker!</h1>
<input type="text" name="bDay" ng-model="mydate | date : 'dd-MM-yyyy'" id="" value="" ng-click="showDatePicker('bday')" />
<div date-picker="mydate" view="year" min-view="date" ng-class="{hidden: (picker !== 'bday')}" auto-close="true"></div>
{{mydate}}
</div>
<script>
var app = angular.module('sample', ['datePicker']);
app.controller('testController', ['$scope', function($scope){
$scope.picker = 'null';
$scope.showDatePicker = function(picker){
$scope.picker = 'null';
setTimeout(function(){
$scope.picker = picker;
$scope.$apply();
}, 100);
}
}]);
</script>
http://plnkr.co/edit/94TifOjXZjEAhA25Kl4A?p=preview
I assume you mean you want it to look like this datepicker. For the most part, it does look like the yearly datepicker from that page. Few differences:
The arrows need the "prev" and "next" classes for proper font sizing
The difference in color is the difference between the "active" and "now" classes being applied to that year box
Your datepicker isn't in a popup since the html is inserted inline, rather than as a grandchild of an element with body as its parent.
If you want any gray dates, you need to apply the "old" class.
Make sure your jquery versions are not clashing.i had the exact same issue and resolved it.You cant use jquery 1.10.4 and 1.1.34....etc...

Resources