ng-class not responding to model update - css

This is very straightforward: My angular view displays rows of printOrders generated via ng-repeat. If a print order has been printed, it applies the class 'panel-pink'
<div class="col-md-12" ng-repeat="printOrder in printOrders | filter: statuses">
<div class='panel mb20 panel-primary panel-hovered' ng-class="{'panel-pink' : {{printOrder.Printed}}}">
<div class="panel-body">
<div style="text-align: center; margin-top: 10px; margin-bottom: 10px;">
<div>{{printOrder.GcodePath}},{{printOrder.Flavor}},{{printOrder.Finishing}}</div>
</div>
<div>
<a class="btn btn-small btn-success btn-sm" ng-click="doPrintOrder(printOrder)">Print</a>
</div>
</div>
</div>
</div>
When it loads the page, it correclty applies the 'panel-pink' class for those that are printed, but when I change the printOrder status via ng-click it doesn't
When a users click on a "print" button the following code on the print order controller executes:
$scope.doPrintOrder = function (printOrder) {
PrintOrdersAPIService.printOrder(printOrder.Id, printOrder.UserId, printOrder.GcodePath).then(function (data) {
printOrder.Printed = true; //this line should change the model
});
}
Everything works ok, the only problem is that the ng-class dosen't get appied when the model changes (printOrder.Printed = true;)
What should I do in order to make the styling work dynamically?

Change your ng-class to this:
ng-class="{'panel-pink' : printOrder.Printed}"
You don't need the curly braces.

Related

Chrome - On adding elements to *ngFor view always scroll down to last element

I have simple page with list of videos. At bottom of page I have button "Load more". If user click that button I make http request and add data to existing array of videos.
Simplified code looks like this:
Component:
export class AppComponent implements OnInit {
public videoList = [];
constructor(private appService: AppService) {}
public ngOnInit(): void {
this.loadVides();
}
public loadMore(): void {
this.loadVides();
}
private loadVides(): void {
this.appService.loadVideos().subscribe((videos) => {
this.videoList = [...this.videoList, ...videos];
console.log('Data was loaded');
})
}
}
Template:
<div *ngFor="let video of videoList">
<div style="height: 100px;">{{video.name}}</div>
</div>
<div class="d-flex justify-content-center mt-2 mb-4">
<button class="btn btn-outline-danger btn-lg" (click)="loadMore()">Load more...</button>
</div>
What a problem is:
At firefox page is not scrolled after more items are loaded, so I see the first of the new items. And at chrome, the page is scrolled to the end, so I see the last new item and 'load more' button again.
Demo:
https://stackblitz.com/edit/angular-ivy-quwfxx?devtoolsheight=33&file=src/app/app.component.html
You can add the overflow-anchor:none like so:-
<div *ngFor="let video of videoList">
<div style="height: 100px;">{{video.name}}</div>
</div>
<div style="overflow-anchor:none" class="d-flex justify-content-center mt-2 mb-4">
<button class="btn btn-outline-danger btn-lg" (click)="loadMore()">Load more...</button>
</div>
The overflow-anchor property enables us to opt out of Scroll Anchoring, which is a browser feature intended to allow content to load above the user’s current DOM location without changing the user’s location once that content has been fully loaded.
I referred this for the answer - https://css-tricks.com/almanac/properties/o/overflow-anchor/
you could blur your button, so chrome won't try to stabilize the scroll position
<button class="btn btn-outline-danger btn-lg" #btn (click)="btn.blur(); loadMore()">Load more...</button>

Apply css based on condition

I am trying to apply a css class based on a condition. This is my code but it does not seem to apply the class correctly.
Basically if selectedEmployee.isHrEmailAddress is true then I want to override section with .section-postal
HTML
<section [ngClass]="{'.section-postal': selectedEmployee.isHrEmailAddress}">
<div class="page-container">
<div id="wrapper">
<form *ngIf="contactDetailsForm" [formGroup]="contactDetailsForm">
<div class="text-left">
<div class="flex flex-row sm:flex-col md:flex-row-reverse lg:flex-col-reverse xl:flex-row">
<div class="check-container text-left" style="width: 450px;">
<div class="flex flex-row sm:flex-col md:flex-row-reverse lg:flex-col-reverse xl:flex-row">
<div class="line">
<p-checkbox name="isHrEmailAddress" formControlName="isHrEmailAddress"
[(ngModel)]="selectedEmployee.isHrEmailAddress" binary="true"
(onChange)="toggle('emailCheckId')">
</p-checkbox>
<span class="ml-2 pt-4" style="font-size: 15px;">I am using my email address on the
member's behalf</span>
</div>
</div>
</div>
</div>
<div class="note" *ngIf="selectedEmployee.isHrEmailAddress">
<span>Please note: You will need to confirm the employee's postal address, so that they can be
contacted in future.</span>
</div>
</div>
</form>
</div>
</div>
</section>
css
section {
height: 500px;
}
.section-postal {
height: 650px;
}
You can use ternary operator in ngClass to select the class based on condition
[ngClass]="selectedEmployee.isHrEmailAddress ? 'section-postal' : 'section'"
You need to remove the dot from the class name in the [ngClass] value.
<section [ngClass]="{'section-postal': selectedEmployee.isHrEmailAddress}">
The dot is used in the CSS selector syntax to denote a class. The class in the HTML should be without the dot.
section { /* denotes the `<section>` tag: type selector syntax */
height: 500px;
}
.section-postal { /* denotes the `section-postal` class: class selector syntax */
height: 650px;
}
In html you must use the class name without the dot.
[ngClass]="{'section-postal': selectedEmployee.isHrEmailAddress}">
You can also use binding, if you just want to override a single class. Here is the documentation, check out the section class property
<section [class.section-postal]="selectedEmployee.isHrEmailAddress"></section>
Here We Go ,
.section-postal { // css file
color:red;
}
i = true; // in ts file
<section [ngClass]="{'section' : i, 'section-postal' : !i }"> //html file
With reference Adding Multiple Class using ngClass :
Adding multiple class using ng-class

ngClass and print media query not working together

I am making an angular component to make a bunch of qr codes and print them. I have a component just for the qr code and want to make it possible to delete a qr code from the list and undo-delete a previously deleted code. I Before adding the undo-delete functionality, everything was working well because I was just removing that particular component from the list. However, now I don't want to completely remove it, I just want to fade it out until print time. I am using ngClass on my div and the "deleted" class does work. Anything that has class noPrint just gets display:none, however when I try to use ngClass to dynamically give a code noPrint, it doesn't set display: none on that particular code.
My qr-code html: The issue is in the first div tag at the top. I have tried adding single quotes on the class names to see if that works as well.
<div
fxLayout="column"
class="qrobj"
[ngClass]="{
deleted: !this.shouldExist,
noPrint: !this.shouldExist
}"
>
<button *ngIf="this.shouldExist" class="noPrint" mat-icon-button>
<mat-icon
matTooltip="Delete this Person?"
matTooltipPosition="after"
color="warn"
(click)="sendDelete()"
>block</mat-icon
>
</button>
<button *ngIf="!this.shouldExist" class="noPrint" mat-icon-button>
<mat-icon
matTooltip="Undo Delete?"
matTooltipPosition="after"
color="primary"
(click)="undoDelete()"
>undo
</mat-icon>
</button>
<div fxLayout="row" class="text">
<p>{{ person.Name }}</p>
<p>{{ person.Name }}</p>
</div>
<div fxLayout="row" class="images">
<img [src]="this.qrlink" (error)="getDefaultUrl()" />
<img [src]="this.piclink" (error)="getDefaultUrl()" />
</div>
</div>
Here is the part of my css that matters:
.deleted {
opacity: 0.3;
}
#media print {
.noPrint {
display: none;
}
}
This is what it looks like
before I delete a Code
This is what it looks like
after I delete a Code:
This is what shows up in the print preview:

How to hide Print button in the print out using #media?

I have a bootstrap column with a button for print which uses media attribute.
<div class="panel-footer">
<div class="row">
<div class="col-md-offset-5 col-md-2">
<button class="btn btn-primary btn-wordwrap" ng-click="$print()" media="print"><span class="glyphicon glyphicon-print"></span> Print</button>
</div>
</div>
</div>
The #media is defined in css as below.
#media print {
button {
display: none !important;
}
}
The $Print() is defined as below in angular controller.
$scope.$print = function () {
window.print();
};
It still prints the Print button in the print out. Any ideas what I am missing here? Thank you!
.hidden-print
See Bootstrap 3 Documentation on Responsive Utilities, Print
http://getbootstrap.com/css/#responsive-utilities-print

div position apply to another div error

I have this example in jsfiddle, first example work great, second example don't work regular, problem is, when i mouse hover on another div, button position apply to first div, not second.
http://jsfiddle.net/GepCL/1/
<div class="wrapper" onmouseover="document.getElementById('button').style.display = 'inline';" onmouseout="document.getElementById('button').style.display = 'none';">
<img id="imgg" src="http://cdn.sheknows.com/articles/2011/05/summer-dresses4.jpg"></img>
<div class="ribbon-wrapper-green"><div class="ribbon-green">NEW</div></div>
<div id="button" class="button" style="display: none;">Add to basket</div>
NEW
Add to basket
http://jsfiddle.net/GepCL/18/
'
<img id="imgg" src="http://cdn.sheknows.com/articles/2011/05/summer-dresses4.jpg"/>
<div class="ribbon-wrapper-green"><div class="ribbon-green">NEW</div></div>
<div id="button" class="button" style="display: none;">Add to basket</div>
<img id="imgg" src="http://cdn.sheknows.com/articles/2011/05/summer-dresses4.jpg"/>
<div class="ribbon-wrapper-green"><div class="ribbon-green">NEW</div></div>
<div id="button2" class="button2" style="display: none;">Add to basket</div>
'
you should put different id for button "add to basket"
The issue is caused by the ID you are using.
As both buttons have the same ID the JavaScript will run until it finds an ID that matches. On hovering over the second div the button will display over the first div because as soon as the JavaScript finds the ID it stops looking as ID's are supposed to be unique.
You could use the next script to make it more automatical and removing the IDs problem:
Javascript:
function fadeOut(div) {
// Remove your DIV with the message Add to basket
var olddiv = document.getElementById('button');
div.removeChild(olddiv);
}
function fadeIn(div) {
// Create a new DIV with your message Add to basket
var newdiv = document.createElement('div');
newdiv.setAttribute('class','button');
newdiv.setAttribute('id','button');
newdiv.innerHTML = 'Add to basket';
div.appendChild(newdiv);
}
HTML:
<div class="wrapper" onmouseover="fadeIn(this);" onmouseout="fadeOut(this);">
<img id="imgg" src="http://cdn.sheknows.com/articles/2011/05/summer-dresses4.jpg" /></img>
<div class="ribbon-wrapper-green"><div class="ribbon-green">NEW</div></div>
</div>
<div class="wrapper" onmouseover="fadeIn(this);" onmouseout="fadeOut(this);">
<img id="imgg" src="http://cdn.sheknows.com/articles/2011/05/summer-dresses4.jpg" /></img>
<div class="ribbon-wrapper-green"><div class="ribbon-green">NEW</div></div>
</div>
Example:
http://jsfiddle.net/GepCL/36/
EDIT: In the code before the button was blinking.
With the next script it is fixed. I've used Jquery to make it easier.
The issue was that adding and removing fires an onmouseout event everytime the DOm is modified.
function fadeOut(div) {
$('#button', $(div)).hide();
}
function fadeIn(div) {
if ($('#button', $(div)).html() == undefined) {
$newdiv = $('<div></div>')
.attr({ id : 'button' })
.addClass("button")
.hide();
$newdiv.text('Add to basket');
$(div).append($newdiv);
}
$('#button', $(div)).show();
}
Example: http://jsfiddle.net/GepCL/57/

Resources