How do I stop Angular from automatically alphabetizing object keys? - javascript

I have this array...
public incidents: any[] = [
{
id: 1,
name: "Default Case Set",
type: "CASEWORK",
str: 34,
mtdna: 0,
ystr: 0,
xstr: 0,
snps: 0
}
]
I'm passing it into a modal like this...
public openEditModal(id: number): void {
this.incidentToBeEdited = this.incidents.filter(result => result.id == id).pop();
const initialState: ModalOptions = {
initialState: {
items: this.incidentToBeEdited,
title: 'Edit Incident'
}
};
// Close modal
this.bsModalRef = this.modalService.show(EditModalComponent, initialState);
}
The problem is that the keys in the object in the incidents array are automatically alphabetized.
When I console the "this.incidentToBeEdited" variable, I get this...
{
mtdna: 0
name: "Default Case Set"
snps: 0
str: 34
type: "CASEWORK"
xstr: 0
ystr: 0
}
So the object that gets sent to the modal (for display purposes) is automatically alphabetized.
I don't want this because I want the fields to appear as they do in the table, which is how they are in the original incidents array.
Is there anyway I can override Angular's need to alphabetize an object?
Here is the code for EditModalComponent...
export class EditModalComponent implements OnInit {
constructor(
public bsModalRef: BsModalRef,
private http: HttpClient,
private formBuilder: FormBuilder) {
this.items = this.items;
this.bsModalRef = this.bsModalRef;
this.editModal = this.formBuilder.group({});
}
// Page loading properties
public httpRequestInProgress: boolean = false;
public pageLoaded: boolean = false;
public pageLoadError: string = '';
public pageLoading: boolean = true;
// Properties
public editModal: FormGroup;
public items?: any;
public title?: string;
// Methods
ngOnInit(): void {
this.editModal = this.formBuilder.group(
this.items
)
console.log("this.items", this.items);
// Remove id from list of items
const itemsInAnArray = [this.items];
itemsInAnArray.forEach((item: any) => delete item.id);
this.pageLoading = false;
this.pageLoaded = true;
}
}
Here is the HTML for EditModalComponent...
<form [formGroup]="editModal" *ngIf="this.items">
<div class="row">
<div class="col-sm-12">
<div *ngFor="let item of this.items | keyvalue">
<div class="col-sm-12 mb-3">
<label class="text-capitalize" for="firstName">{{item.key}}</label>
<input class="form-control"
id="{{item.key}}"
value="{{item.value}}"
formControlName="{{item.key}}">
</div>
</div>
</div>
<div class="mt-3">
<button class="btn btn-primary float-start"
type="button"
(click)="saveAsync()">
Save
</button>
<button class="btn btn-secondary me-1 float-start"
type="button"
(click)="bsModalRef.hide()">
Cancel
</button>
</div>
</div>
</form>
```

Related

Angular How to send value from one Sibling to another and send it back changed to the first sibling

I'd like to ask how can I send data from one sibling component to another and send it back with changed value?
I need to add bootstrap effect fadeInDown to a newly added comment in my comments section.
It works but unfortunately it affects all of the comments when I reload the page and the effect is also added when I edit a comment.
I need to send boolean value on method addComment from new-comment component to comment component but then I need that value in new-component to become false again. Now it's false and after using addComment method it becomes true forever. How can I handle this?
I will be glad for any advice
This is my comment section:
Comment section
This is the structure of my files: Files structure
These are the components I'm working on:
Comment section HTML
<h6>Comments: ({{commentsCount}})</h6>
<app-new-comment class="d-block mt-3" [requestId]="requestId" (update)="updateComments()">
</app-new-comment>
<app-comment *ngFor="let comment of comments; let i = first"
[ngClass]="{'fadeInDown': i}"
class="d-block mt-3 animated"
[comment]="comment"
(update)="updateComments()"></app-comment>
Comment section TS
export class CommentSectionComponent implements OnInit, OnDestroy {
#Input() requestId: string
comments: CommentDetailsDto[]
commentsCount = 0
private subscription: Subscription
constructor(
private commentsService: CommentsService,
private alert: AlertService
) {
}
ngOnInit(): void {
this.updateComments()
}
ngOnDestroy(): void {
this.unsubscribe()
}
updateComments(): void {
this.unsubscribe()
this.subscription = this.commentsService.getComments(this.requestId)
.subscribe({
next: (comments: CommentDetailsDto[]) => {
this.comments = comments.reverse()
this.commentsCount = this.getCommentsCount(comments)
},
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
}
})
}
private getCommentsCount(comments: CommentDetailsDto[]): number {
return comments.reduce(
(cnt, comment) => cnt + 1 + (comment.replies ? this.getCommentsCount(comment.replies) : 0),
0
)
}
private unsubscribe(): void {
if (this.subscription instanceof Subscription) {
this.subscription.unsubscribe()
}
}
}
Comment section SCSS
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInDown {
animation-name: fadeInDown;
}
New comment component HTML
<div class="d-flex">
<app-user-image class="mr-3"></app-user-image>
<textarea #textArea class="d-block" placeholder="Add comment" [(ngModel)]="newComment">
</textarea>
</div>
<div class="text-right mt-3">
<button class="btn btn-primary font-weight-bold px-5" type="button"
[disabled]="!newComment" (click)="submit()">
Post
</button>
</div>
New comment TS
export class NewCommentComponent implements OnInit {
#ViewChild('textArea') textArea: ElementRef<HTMLTextAreaElement>
#Input() requestId?: string
#Input() comment?: CommentDetailsDto
#Output() update = new EventEmitter()
newComment: string
private readonly commentResponseObserver = {
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
delete this.newComment
this.update.emit()
this.alert.showSuccess('Comment submitted successfully')
}
}
constructor(
private commentsService: CommentsService,
private alert: AlertService,
private route: ActivatedRoute
) {
}
ngOnInit(): void {
if (this.comment) {
this.textArea.nativeElement.focus()
}
}
submit(): void {
if (this.requestId) {
this.addComment()
} else if (this.comment) {
this.addReply()
}
}
addComment(): void {
if (this.newComment) {
this.commentsService.addComment(this.requestId, this.newComment)
.subscribe(this.commentResponseObserver)
}
}
addReply(): void {
if (this.newComment) {
this.commentsService.addReply(this.route.snapshot.queryParamMap.get('requestId'), this.comment, this.newComment)
.subscribe(this.commentResponseObserver)
}
}
}
Comment component HTML
<div class="comment">
<app-user-image></app-user-image>
<div class="position-relative d-inline-block flex-fill">
<div class="d-flex justify-content-between align-items-center">
<div><strong>{{comment.author.name}} / {{comment.author.id}}</strong><span
class="date">{{comment.created | krakenDateTime}}</span></div>
<div class="actions">
<button *ngIf="this.hateoas.supports(comment, 'update') && !edit"
type="button" class="bg-transparent border-0" title="Edit"
(click)="toggleEdit()"><i class="icon-kraken icon-kraken-edit"></i></button>
<button *ngIf="this.hateoas.supports(comment, 'delete')"
type="button" class="bg-transparent border-0" title="Delete"
(click)="displayDeletionConfirmation()"><i class="icon-kraken icon-kraken-trash"></i></button>
</div>
</div>
<textarea *ngIf="edit; else readonlyComment"
#textarea
class="d-block w-100"
style="min-height: 7rem;"
[rows]="rows()"
[(ngModel)]="commentContent"></textarea>
<ng-template #readonlyComment>
<div [innerHTML]="commentContentHtml()"></div>
</ng-template>
<strong *ngIf="showReplyButton"
class="reply-button"
(click)="toggleReplyComponent()">Reply</strong>
</div>
</div>
<div *ngIf="edit" class="animated fadeIn text-right mt-3">
<button class="btn btn-sm discard" (click)="cancelEdit()">Discard</button>
<button class="btn btn-sm ml-2 update" (click)="updateComment()">Update</button>
</div>
<div class="replies">
<app-new-comment *ngIf="showNewReplyWindow"
class="d-block mt-3"
[comment]="comment"
(update)="this.update.emit()"></app-new-comment>
<app-comment *ngIf="firstReply"
class="d-block my-3"
[comment]="firstReply"
(update)="update.emit()"></app-comment>
<div *ngIf="moreReplies.length" class="replies-toggle" (click)="showMoreReplies =
!showMoreReplies">
<div class="horizontal-bar"></div>
<span class="mx-3">{{showMoreReplies ? 'Hide' : 'See'}} {{moreReplies.length}} more
comments</span>
<div class="horizontal-bar"></div>
</div>
<div *ngIf="showMoreReplies">
<app-comment *ngFor="let reply of moreReplies"
class="d-block my-3"
[comment]="reply"
(update)="update.emit()"></app-comment>
</div>
<span id="temporaryLastRow"></span>
Comment TS
export class CommentComponent implements OnInit {
#ViewChild('textarea', {static: true}) textarea: ElementRef<HTMLTextAreaElement>
#Input() comment: CommentDetailsDto
#Output() update = new EventEmitter()
edit = false
showReplyButton = false
showNewReplyWindow = false
showMoreReplies = false
commentContent: string
firstReply: CommentDetailsDto
moreReplies: CommentDetailsDto[]
constructor(
private commentsService: CommentsService,
private modalFactoryService: ModalFactoryService,
public hateoas: HateoasService,
private alert: AlertService
) {
}
ngOnInit(): void {
this.commentContent = this.comment.content
this.showReplyButton = this.hateoas.supports(this.comment, 'reply')
this.moreReplies = this.comment.replies.reverse().slice(1)
this.firstReply = this.comment.replies[0]
}
toggleEdit(): void {
this.edit = !this.edit
}
updateComment(): void {
this.commentsService.updateComment(this.comment, this.commentContent)
.subscribe({
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
this.alert.showSuccess('Comment updated successfully')
this.update.emit()
}
})
}
cancelEdit(): void {
this.edit = false
this.commentContent = this.comment.content
}
displayDeletionConfirmation(): void {
this.modalFactoryService.openConfirmationModal(
'Delete Comment',
{
message: 'Are you sure you want to delete this comment?',
yesOptionButton: 'Yes',
noOptionButton: 'No'
},
() => {
this.hateoas.execute(this.comment, 'delete')
.subscribe({
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
this.alert.showSuccess('Comment deleted successfully')
this.update.emit()
}
})
}
)
}
toggleReplyComponent(): void {
this.showNewReplyWindow = !this.showNewReplyWindow
}
commentContentHtml(): string {
return this.commentContent.replace(/\n/g, '<br>')
}
rows(): number {
const newLines = this.commentContent.match(/\n/g) || []
return newLines.length + 1
}
}
export interface Author {
id: string
name: string
}
export interface CommentDetailsDto extends Resource {
content: string
author: Author
replies: CommentDetailsDto[]
created: string
}

Angular component doesn't assign value from observable service getter, why?

I'm working on building a set of filters, so I'm just trying to make use of the salesChannels array content in my view, which only gets populated when clicking the button with the test() function. The log in ngOnInit outputs an empty array the first time, but works correctly after pressing the button.
The getOrganisationChannels returns an observable.
What causes this behavior and how do I handle it properly? I tried using an eventEmitter to try and trigger the populating but that doesn't work.
TYPESCRIPT
export class SalesChannelFilterComponent implements OnInit {
constructor(
public organizationService: OrganizationService
) { }
#Input() organizationId: any;
salesChannels: Array<any> = [];
selectedChannels: Array<any> = [];
allSelected: Array<any> = [];
ngOnInit() {
this.getChannels();
console.log(this.salesChannels);
}
getChannels() {
this.organizationService.getOrganizationChannels(this.organizationId).subscribe(
salesChannels => {
this.salesChannels = salesChannels;
})
}
test() {
console.log(this.salesChannels);
}
}
HTML
<div>
{{ salesChannels | json }}
</div>
<button (click)="test()">test</button>
<div *ngFor="let channel of salesChannels; let i = index;" class="checkbox c-checkbox">
<label>
<input type="checkbox">
<span class="fa fa-check"></span>{{channel.name}}
</label>
</div>
This is expected behaviour since you are populating the salesChannel in the subscription of an Observable. It's recommended that you use aysnc pipe to let angular check for changes and update the view accordingly.
Component.ts :
export class SalesChannelFilterComponent implements OnInit {
constructor(
public organizationService: OrganizationService
) { }
#Input() organizationId: any;
salesChannels$!: Observable<Array<any>>;
selectedChannels: Array<any> = [];
allSelected: Array<any> = [];
ngOnInit() {
this.getChannels();
console.log(this.salesChannels);
}
getChannels() {
this.salesChannels$ = this.this.organizationService.getOrganizationChannels(this.organizationId);
}
test() {
console.log(this.salesChannels);
}
}
In your template:
<button (click)="test()">test</button>
<div *ngFor="let channel of salesChannels$ | async; let i = index;" class="checkbox c-checkbox">
<label>
<input type="checkbox">
<span class="fa fa-check"></span>{{channel.name}}
</label>
</div>
More details: https://angular.io/api/common/AsyncPipe
I recommend using AsyncPipe here:
<div>{{ salesChannels | async}}</div>
and in .ts:
salesChannels = this.organizationService.getOrganizationChannels(this.organizationId)

Angular display Filtering Incorrectly

When a user selects a tag, I want to display only the blogs containing that tag.
For example when a user selects the '#C#' tag only posts with this tag will be displayed.
My set up is as follows: I have an array of blogs which contain post tags which contain tags:
export interface IBlog
{
id: number
title: string
content: string
subscription: number
time: string
created: Date;
imageUrl: string
coverImage: string
image: string
likes: number
body: string
comments?:{
message: string
handle: string,
city: string,
country: string
},
articleLinkUrl?: string,
sessions: ISession[],
mainComments: IComments[],
postTags: IPostTags[]
}
export interface ISession
{
id: number,
name: string,
presenter: string,
duration: number,
level: string,
abstract: string,
voters: string[]
}
export interface IComments
{
id: number,
message: string
}
export interface IPostTags
{
id: number,
tag: ITag[]
}
export interface ITag
{
id: number,
name: string
}
I have a blog-list.component.ts:
import {Component, OnInit} from '#angular/core'
import { BlogService} from './shared/blog.service';
import { ActivatedRoute } from '#angular/router';
import { IBlog } from './shared';
#Component({
template: `
<div>
<h1>Upcoming Blogs</h1>
<hr/>
<div class= "btn-group btn-group-sm">
<button class="btn btn-default" [class.active] = "filterBy==='all'" (click) = "filterBy='all'">All</button>
<button class="btn btn-default" [class.active] = "filterBy==='c#'" (click) = "filterBy='#C#'">C#</button>
<button class="btn btn-default" [class.active] = "filterBy==='angular'" (click) = "filterBy='#Angular'">Angular</button>
<button class="btn btn-default" [class.active] = "filterBy==='netcore'" (click) = "filterBy='#NetCore'">.NET Core</button>
</div>
<div class ="row">
<blog-thumbnail [filterBy]="filterBy" [blogs] = "blogs"></blog-thumbnail>
<div class='row' style="margin-bottom: 10px;">
<div class="col-md-2">
<h3 style="margin:0">Sort by Tag</h3>
</div>
<div class="col-md-7">
<div class= "btn-group btn-group-sm" style="margin-right: 20px; margin-left: 20px;">
<button class="btn btn-default" [class.active] = "sortBy==='name'" (click) = "sortBy='name'">By Name</button>
<button class="btn btn-default" [class.active] = "sortBy==='votes'" (click) = "sortBy='votes'">By Votes</button>
</div>
</div>
</div>
</div>
</div>`
})
export class BlogListComponent implements OnInit{
blogs:IBlog[]
filterBy: string = 'all';
constructor(private blogService: BlogService, private route: ActivatedRoute){
}
ngOnInit(){
this.blogs = this.route.snapshot.data['blogs']
}
}
This displays a blog-thumbnail component
import {Component, Input, EventEmitter, Output, OnChanges} from '#angular/core'
import { forEach } from '#angular/router/src/utils/collection';
import { IBlog, IPostTags } from './shared';
#Component ({
selector: 'blog-thumbnail',
template: `
<div class="row" *ngFor="let blog of blogsSession">
<div [routerLink] = "['/blogs', blog.id]" class="well hoverwell thumbnail">
<img src={{blog?.coverImage}}/>
<h2>{{blog?.title | uppercase}}</h2>
<div>{{blog?.created | date}}</div>
<div>Content: {{blog?.content}}</div>
<div>Tags: {{blog?.content}}</div>
<div well-title *ngIf="blog?.mainComments">
{{blog?.likes}} Reactions
<i *ngIf="blog?.likes >= 1" class="glyphicon glyphicon-heart-empty" style="color:red"></i>
{{blog.mainComments.length}} Comments
<i *ngIf="blog.mainComments.length >= 1" class="glyphicon glyphicon-comment" ></i>
</div>
<div well-title *ngIf="blog?.postTags">
{{blog.postTags.length}} Post Tags
<i *ngIf="blog.postTags.length >= 1" class="glyphicon glyphicon-comment" ></i>
</div>
</div>
`,
styles:[
`
.thumbnail {min-height: 210px;}
.pad-left {margin-left: 10px;}
.well div { color: #bbb;}
`]
})
export class BlogThumbnailComponent implements OnChanges {
#Input() blog: IBlog
#Input() filterBy: string;
#Input() blogs: IBlog[];
blogsSession: IBlog[] = [];
getStartTimeStyle(): any{
if (this.blog && this.blog.time === '7:30pm')
return{color: '#003300', 'font-weight' : 'bold'}
return{};
}
ngOnChanges(){
if(this.blogs){
this.filterSessions(this.filterBy);
//this.sortBy === 'name' ? null : null;
}
}
filterSessions(filter){
if(filter === 'all'){
this.blogsSession= this.blogs.slice(0);
}
else
{
this.blogsSession = this.blogs.filter(blog => {
return blog.postTags.filter( postTag =>{
postTag.tag.name === filter
})
})
this commented out code works but it is not what i want
// this.blogsSession = this.blogs.filter(blog => {
// return blog.postTags.length < 2;
//})
}
}
}
The following section off code is where I am having my problem. It does not work:
this.blogsSession = this.blogs.filter(blog => {
return blog.postTags.filter( postTag =>{
postTag.tag.name === filter
})
})
I have spent a large amount of time on this. Would anybody be able to explain what I am doing wrong here?
The function used in the filter() method should return true or false (or actually a value that coerces to true or false). Your function returns an array; you are filtering blog.postTags.
Try this instead:
this.blogsSession = this.blogs.filter(blog => {
return blog.postTags.some(postTag => postTag.tag.name === filter)
})
The some() method will return true if at least one of the items in the array meet the conditions used in the function.
Why do you have 2 filter operators? I think this:
this.blogsSession = this.blogs.filterpostTags.filter( postTag =>{
postTag.tag.name.toLocaleLowerCase() === filter.toLocaleLowerCase()
})
should be enough.

How can I access certain element's key in local storage?

I have an array of objects like this and when I click the Remove Favorite button I want to delete the certain element from local storage. I'm deleting from the page with the removeLocal() function but it only deletes from the page, not from local storage. I want to delete it both. I'm generating random number when assigning local storage key. Is there way to access this key and delete the item?
html:
<input type="text" [(ngModel)]="profile" (ngModelChange)="detectChange($event)" (keyup)="findProfile()"
placeholder="Enter the username..." class="input">
<div style="background-color: lightslategrey;">
<ng-template [ngIf]="profile !== '' && user">
<img [src]="user.avatar_url" alt="" class="userAvatar">
<p>Username: {{user.login}}</p>
<p>Location: {{user.location}}</p>
<p>E-mail: {{user.email}}</p>
<p>Blog Link: {{user.blog}}</p>
<p>Member Since: {{user.created_at}}</p>
<button [routerLink]="['', user.login.toLowerCase(), user.id ]" class="viewProfileButton" a>View
Profile</button><br>
<button (click)="localStorage()" class="viewProfileButton">Add to Favorite</button>
</ng-template>
</div>
<div *ngIf="closeDiv">
<div style="background-color: rgb(106, 106, 170);" *ngFor="let item of display">
<p>Username: {{item.login}}</p>
<p>Location: {{item.location}}</p>
<p>ID: {{item.id}}</p>
<button (click)="removeLocal(item.id)" class="viewProfileButton">Remove Favorite</button>
</div>
</div>
<button (click)="consoleLog()" class="viewProfileButton">Console Log</button>
<router-outlet></router-outlet>
ts:
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
user: any;
profile: any;
display: any;
local: any;
randomNumber: any;
randomString: any;
idString: any;
keys: any;
closeDiv: boolean = true;
constructor(private userData: HttpService) {}
ngOnInit() {
this.display = Object.values(localStorage).map((val: any) => JSON.parse(val));
console.log('ngOnInit Works', this.display);
}
findProfile() {
this.userData.updateProfile(this.profile);
this.userData.getUser().subscribe((result) => {
this.user = result;
});
}
localStorage(id: any) {
this.randomNumber = Math.floor(Math.random() * 10000);
this.randomString = this.randomNumber.toString();
localStorage.setItem(this.randomString, JSON.stringify(this.user));
this.display = Object.values(localStorage).map((val: any) => JSON.parse(val));
console.log(this.display);
}
removeLocal(id: any) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
this.display.splice(i, 1);
}
}
}
detectChange(ev: any) {
ev.length > 0 ? (this.closeDiv = false) : (this.closeDiv = true);
}
}
Add the call localStorage.removeItem(key) to your removeLocal function. Granted, you need to store your random keys somewhere, otherwise you will have to integrate this solution to parse through them.
removeLocal(id: any, key: string) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
this.display.splice(i, 1);
localStorage.removeItem(key); // here
}
}
}
EDIT: After a conversation in the comments, this solution can be simplified to remove a variable from the function header by storing a storageKey variable within display.
removeLocal(id: any) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
localStorage.removeItem(this.display[i].storageKey);
this.display.splice(i, 1);
}
}
}

Bug with saving editing item in table-list

I have marketing "campaign" in application.
There is also table of all campaigns which user can edit.
After editing campaign and click Save there in table of campaign appear duplication of that campaign.
After refresh the page that duplication of campaign disappears.
That means there is duplicate of campaign which is not saved in database, only in that table (list) which after refreshing page disappears.
Expected result: On save editing campaign there shouldn't appear duplication of campaign.
Does someone have some idea what can be the problem?
Here is typescript file of list component:
export class NanoCampaignListComponent implements OnChanges {
#Input() advertiserId: string;
#Input() advertiserIoId: string;
#Input() insertionOrderTargeting: string;
// public advertiserId: string;
// public advertiserIoId: string;
public campaignListDto: CampaignListDto;
public campaignListDtoData: CampaignListDtoData;
public columnsArray = TABLE_COLUMNS;
private subscription: Subscription;
constructor(private campaignModel: CampaignModel,
private modalModel: ModalModel,
private activatedRoute: ActivatedRoute) {
// this.subscribeToRouteParamsChange();
}
public ngOnChanges(): void {
this.getListDto();
this.getListDtoData();
}
public getCampaignModel(): CampaignModel {
return this.campaignModel;
}
// public ngOnDestroy() {
// this.subscription.unsubscribe();
// }
public openModal(id: string): void {
const data = {
id: id,
advertiserId: this.advertiserId,
insertionOrderId: this.advertiserIoId,
insertionOrderTargeting: this.insertionOrderTargeting
};
this.modalModel.add(CampaignModel.ENTITY_NAME, data);
}
private getListDto(): void {
this.campaignListDto = this.campaignModel.getListDto(this.advertiserIoId);
// this.campaignListDto = this.campaignModel.getListDto(this.advertiserId);
}
private getListDtoData(): void {
this.campaignModel
.getListDtoData(this.campaignListDto)
.catch(error => console.log(error))
}
Here is the INITIAL list component.html for table:
<div class="nano-f nano-f-c">
<div class="nano-f-40 nano-f-r">
<nano-add-new-button class="nano-bc-yellow hover-effect" (click)="openModal('new')">
</nano-add-new-button>
</div>
<nano-table *ngIf="campaignListDto.isLoaded === true"
[#fadeIn]="'in'"
[tableList]="campaignListDto.list"
[columnsArray]="columnsArray"
[pageCount]="5"
[sortField]="'impressions'"
[sortInverse]="true">
<ng-template let-campaignListDtoData="item">
<div class="nano-table-entity-name-cell">
<span [tooltip]="campaignListDtoData.name"
[routerLink]="['/private/advertiser/' + advertiserId + + '/advertiserIo/' + advertiserIoId +'/campaign/' + campaignListDtoData.id]"
class="nano-c-p">
{{ campaignListDtoData.name }}
</span>
<span>
{{ campaignListDtoData.id }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.revenue | number:'.2-2' }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.cost | number:'.2-2' }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.impressions | number }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.clicks | number }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.CTR | number }}
</span>
</div>
<div class="nano-table-number-cell">
<span>
{{ campaignListDtoData.conversions | number }}
</span>
</div>
<div class="nano-table-actions-cell">
<span class="btn-tables-default"
(click)="openModal(campaignListDtoData.id)">
<i class="fa fa-external-link"></i>
</span>
<nano-entity-toggle-button #entityToggleButton>
</nano-entity-toggle-button>
<nano-campaign-duplicate [campaignId]="campaignListDtoData.id">
</nano-campaign-duplicate>
<!--<nano-entity-duplicate-button [entityId]="campaignListDtoData.id"-->
<!--[entityModel]="getCampaignModel()">-->
<!--</nano-entity-duplicate-button>-->
<nano-entity-delete-button [entityId]="campaignListDtoData.id"
[entityName]="campaignListDtoData.name"
[entityParentId]="advertiserIoId"
[entityModel]="getCampaignModel()">
</nano-entity-delete-button>
</div>
<div class="nano-table-number-cell">
<span>
<i class="fa fa-circle"
[class.nano-c-green]="campaignListDtoData.status === 1"
[class.nano-c-red]="campaignListDtoData.status === 2"></i>
</span>
</div>
<nano-campaign-edit *ngIf="entityToggleButton.isOpen"
[campaignId]="campaignListDtoData.id"
[advertiserId]="advertiserId"
[advertiserIoId]="advertiserIoId"
[insertionOrderTargeting]="insertionOrderTargeting"
class="nano-table-preview-cell">
</nano-campaign-edit>
</ng-template>
</nano-table>
<div *ngIf="campaignListDto.isLoaded === true"
class="nano-f-30 nano-f-r">
<span class="nano-m-a5">
Statistics are for last 7 days.
</span>
</div>
<nano-loading-indicator *ngIf="campaignListDto.isLoaded === false"
[#flyIn]="'in'">
</nano-loading-indicator>
nano-campaign-edit comp:
export class NanoCampaignEditComponent implements OnInit {
#Input() advertiserId: string;
#Input() advertiserIoId: string;
#Input() campaignId: string;
#Input() insertionOrderTargeting: string;
#Output() campaignIdChange = new EventEmitter();
#ViewChild('mappingComponent') mappingComponent: NanoMappingComponent;
public campaignDto: CampaignDto;
public entityName = CampaignModel.ENTITY_NAME;
constructor(public campaignModel: CampaignModel) {
}
public ngOnInit(): void {
this.getDto();
this.getDtoData();
}
public onCampaignSave(): void {
this.campaignIdChange.emit(this.campaignDto.id);
this.campaignModel.deliveryLimitationConflictCheck(this.campaignDto.id);
}
// retrive campaign which is clicked to be edited
private getDto(): void {
this.campaignDto = this.campaignModel.getDto(this.campaignId, this.advertiserId, this.advertiserIoId);
}
// retrive all data of campaign which is clicked to be edited
private getDtoData(): void {
this.campaignModel
.getDtoData(this.campaignDto)
.catch(error => console.log(error))
}
nano-campaing-edit- template: (small part of code)
<nano-entity-footer [entityDto]="campaignDto"
[entityModel]="campaignModel"
[parentForm]="campaignForm"
(onEntityDtoSave)="onCampaignSave()">
</nano-entity-footer>
nano-table.ts, here is part of code which maybe can be important for this case:
export class NanoTableComponent {
#ContentChild(TemplateRef) template: TemplateRef<any>;
#Input() columnsArray: Array<NanoTableHeader> = [];
#Input() isAsync: boolean = false;
#Input() nanoTable: NanoTable;
#Input() pageCount: number = 10;
#Input() pageCountOptions: Array<number> = [5, 10, 20];
#Input() sortField: string | null = null;
#Input() sortInverse: boolean = false;
#Input() useQueryParams: boolean = true;
#Input() hasExport: boolean = false;
#Input()
public set tableList(value: Array<any>) {
this._tableList = value;
this.onTableListChange();
}
public get tableList(): Array<any> {
return this._tableList;
}
private _tableList: Array<any> = [];
constructor(private router: Router,
private activatedRoute: ActivatedRoute) {
}
}
nano-table template:
<div *ngIf="tableList.length > 0"
class="nano-table-grid nano-mt-5">
<div class="nano-f-r">
<input type="text" [(ngModel)]="searchWord" class="nano-white-smoke-input" placeholder="Search"/>
<button *ngIf="hasExport === true && isExportInProgress === false"
type="button"
class="nano-f-250 nano-white-smoke-button nano-ml-2"
(click)="exportReport()">
<span>
CSV
</span>
</button>
<nano-loading-indicator *ngIf="isExportInProgress === true"
class="nano-loading-bar-small nano-loading-bar-overlay nano-f-250 "
style="margin-left: 2px"></nano-loading-indicator>
</div>
<div class="nano-table-row nano-table-grid-header">
<div class="{{column.columnClass}}"
*ngFor="let column of columnsArray"
[ngClass]="{'sort-active':sortField === column.columnField}"
(click)="onSortFieldChange(column.columnField)">
<span>
{{column.columnName}}
</span>
<i class="fa"
[class.fa-sort-asc]="sortInverse === true && sortField === column.columnField"
[class.fa-sort-desc]="sortInverse === false && sortField === column.columnField">
</i>
</div>
</div>
<div class="nano-f-c nano-table-row-wrapper"
*ngFor="let item of getFilteredList()">
<div class="nano-table-row">
<ng-template [ngTemplateOutlet]="template"
[ngOutletContext]="{item: item}">
</ng-template>
</div>
</div>
<nano-table-footer [pageNumber]="pageNumber"
[pageCount]="pageCount"
[pageCountOptions]="pageCountOptions"
[length]="getLengthForFooter()"
(onPageNumberChange)="onPageNumberChange($event)"
(onPageCountChange)="onPageCountChange($event)">
</nano-table-footer>

Categories

Resources