ng-select add new option with async search - javascript

I use the [#ng-select/ng-select][1] component many places in my software. It works well, it searches by a backend method as the user types and shows the results for selection.
Now I would like to let the user to create new items that are not on the list. How can I do this with an async list? productNames is an Observable.
<ng-select [name]="'productname'+index$" [items]="productNames | async"
[attr.id]="'productname'+index$"
[(ngModel)]="detail.productNameNew"
[typeahead]="productNameInput"
(change)="productNameChanged($event, detail)"
(keydown)="productNameKeyPress($event, detail)"
[disabled]="currentSuggestion.acceptUser === null ? null : true"
[clearable]="false">
<ng-template ng-label-tmp let-item="item">
{{item.productName}}
</ng-template>
<ng-template ng-option-tmp let-item="item">
<div class="noproduct-item">
<div class="noproduct-head">
<div class="productname">{{item.productName}}</div>
<div class="description">{{item.description}}</div>
</div>
<div class="noproduct-details">
<div class="headid">
<span class='glyphicon glyphicon-send'></span>
{{item.suggestionHeadId}}
</div>
<div class="createduser">
<span class='glyphicon glyphicon-user'></span>
{{item.createUser?.name}}
</div>
<div class="createddate">
<span class='glyphicon glyphicon-calendar'></span>
{{item.createDate | date: 'yyyy.MM.dd.'}}
</div>
</div>
</div>
</ng-template>
</ng-select>

Add a second observable to capture the user added products and then use combineLatest to merge them. Subscribing to the combined list will produce a new list that you can use in the ng-select.
https://stackblitz.com/edit/angular-rxjs-combinelatest

Related

can't reach inner inner object using keyvalue pair in Angular with firebase

I have a json object that has an inner object called data, which has data: {count: 9, message: "9 sites synced"} - also json object. I'm trying to get the value from message, not from count. Here is my template code:
<div class="full-width border-radius-4 overflow-hidden">
<!-- Header -->
<div class="head accent p-24 pb-16" fxLayout="column" fxLayoutAlign="space-between">
<div fxLayout="row" fxLayoutAlign="end center">
</div>
</div>
<mat-accordion class="full-width example-headers-align" multi *ngIf="liveActions$ | async as actions; else: loading">
<mat-expansion-panel *ngFor="let action of actions">
<mat-expansion-panel-header *ngIf="action.type == 'single'">
<mat-panel-description fxFlex="30%">
<div class="lgreen material-icons" *ngIf="action.status == 'completed'">done_all</div>
<div class="red material-icons" *ngIf="action.status == 'pending'">pending_actions</div>
<div class="blue material-icons" *ngIf="action.status == 'queued'">pending</div>
<div class="yellow material-icons" *ngIf="action.status == 'error'">error</div>
</mat-panel-description>
<mat-panel-description fxFlex="40%">{{action.key}}</mat-panel-description>
<div *ngFor="let dataItem of action?.data | keyvalue">{{dataItem?.value?.message}}
</div>
<!-- <mat-panel-description>{{action.startDate | date:'medium'}}</mat-panel-description>-->
</mat-expansion-panel-header>
</div>
</mat-expansion-panel>
</mat-accordion>
<ng-template #loading>Loading…</ng-template>
</div>
when I do {{dataItem?.value?.message}} I get nothing. When I do dataItem.value, I get the values for both count and message.
I need only the value from message. What am I doing wrong??
with keyvalue pipe on your object it will convert the action.data object to below array
[{key:count, value: 9}, {key:message,value:'9 sites synced'}]
if you iterate over the above object :
dataItem?.value?.message = undefined
dataItem.value = 9 and 9 sites synced
Which is what u r seeing.
You can just add a condition when binding the value what to show
{{ dataItem.key === 'message' ? dataItem.value: ' '}}
there are other ways also...I think you can figure out now what was happening and what needs to be done as per your requirement.

How to loop through unknow number of nested json object in Angular with ngFor?

I'm trying to display all the reply from this json :
https://www.reddit.com/r/AskReddit/comments/k8w43d/people_with_the_last_name_pepper_who_have.json
So, depending of the post im loading and the reply, my number of children will differ. How can I loop throught it until I reach the last reply with children (body[2].data.children) ?
Like this :
<div class="replies-box" *ngFor="let reply of comments.body[1].data.children">
<div class="reply-header">
<p class="reply-author"><b>From</b> : {{ reply.data.author }}</p>
<p class="reply-send"><b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</div>
I have only the first level of reply, is there a way to simply loop through them all ?
Thanks in advance.
I would use a recursion type of approach.
Develop a app-comment component and if comment has children, loop over the children and display the app-comment. That way it will loop over the comments until no more children
<div *ngIf='comment'>
<span *ngIf='comment.kind; else showComment'>Kind: {{ comment.kind }}</span>
<ng-template #showComment>
<span>{{ comment }}</span>
</ng-template>
<div>
<app-comment *ngFor='let child of comment.data?.children' [comment]='child'> </app-comment>
</div>
</div>
See this sample illustration
Simply use ngFor inside ngFor with help of ng-container (will not create extra dom elements)
<div class="replies-box">
<ng-container *ngFor="let commentBody of comments.body">
<ng-container *ngFor="let reply of commentBody.data.children">
<div class="reply-header">
<p class="reply-author">
<b>From</b> : {{ reply.data.author }}
</p>
<p class="reply-send">
<b>Send</b> : {{ this.getDateReply(reply.data.created_utc) }}
</p>
</div>
<div class="text-first-reply" [innerHTML]="this.getHtmlDecode(reply.data.body_html)">
</div>
</ng-container>
</ng-container>
</div>

How an i change the pagination-control numbers(1 2 3) to other values like 'Anything1 Anything2 ...' using ngFor* on array in ngx-pagination?

Is it possible to replace ngx-pagination's 'pagination-control'? By defaults, page numbers are showing like '1 2 3'. And I want to replace them with a string value in the array.
<pagination-controls (pageChange)="pageChange($event)" class="my-pagination"></pagination-controls>
The above code will display pagination numbers like
I want to replace the number with values from an array [Anything1, Anything2, Anything3].
Here my data is fixed and I know my page number count and its details.
You need to have look at custom template of ngx-pagination. In customization part you may try to add your Anything before {{page.label}}.
Custom Template example can be found here. http://michaelbromley.github.io/ngx-pagination/#/custom-template
<pagination-template #p="paginationApi"
[id]="config.id"
(pageChange)="config.currentPage = $event">
<div class="custom-pagination">
<div class="pagination-previous" [class.disabled]="p.isFirstPage()">
<a *ngIf="!p.isFirstPage()" (click)="p.previous()"> < </a>
</div>
<div *ngFor="let page of p.pages" [class.current]="p.getCurrent() === page.value">
<a (click)="p.setCurrent(page.value)" *ngIf="p.getCurrent() !== page.value">
<span>Anything{{ page.label }}</span>
</a>
<div *ngIf="p.getCurrent() === page.value">
<span>Anything{{ page.label }}</span>
</div>
</div>
<div class="pagination-next" [class.disabled]="p.isLastPage()">
<a *ngIf="!p.isLastPage()" (click)="p.next()"> > </a>
</div>
</div>
</pagination-template>

How to limit repeated number of items in ng-repeat. angularjs?

I'm working in contact card. I need to add Name and contact number in the list. But the condition is Name and contact must be added only 2 times. for ex.
Contact Card-1
Name-A
Name-B
Contact-1
Contact-2
Whenever I click on the button my name and contact get added in the list but with certain condition.
My code is
<md-list-item ng-show="showContactList" class="md-2-line" ng-repeat="numbers in contactList track by $index" >
<i ng-show="numbers.type == 'test'" class="material-icons md-avatar-icon">textsms</i>
<i ng-show="numbers.type == 'CELL' || numbers.type == 'EXT'" class="material-icons md-avatar-icon">phone</i>
<div class="md-list-item-text" ng-class="{'md-offset': phone.options.offset }">
<h3> {{ numbers.type }} </h3>
<p> {{ numbers.value }} </p>
</div>
<i class="material-icons md-avatar-icon add-rm-icon margin-right" ng-click="arrayText.push(numbers);">add</i>
</md-list-item>
You can use:
<div ng-repeat="item in items | filter:{visible: true} | limitTo: 50">
<p>{{item.id}}</p>
</div>
{visible- true} will return a list of all visible items
You can take a look at the angularjs docu for more information on the filter filter. http://docs.angularjs.org/api/ng.filter:filter

Protractor - get text of a child element in ng-repeat

I'm using Protractor to test an angular page. This page has a table populated by ng-repeat and I would like to extra the text within that table. Here is the HTML code:
<div class="data-group ng-scope" ng-repeat="group in tableData | filter: filterText | orderBy: getValueToOrderByGroup() : sortingCriteria.descending" ng-show="filtered.length > 0">
<div class="data-row group-header">
<div class="col-md-6">
<i ng-click="group.hideRows = !group.hideRows" ng-class="{'rotate-down': group.hideRows}" class="fa fa-fw fa-chevron-right"></i>
<strong class="text-capitalize ng-binding" ng-click="group.hideRows = !group.hideRows"> HEADER TEXT </strong>
</div>
</div>
<div collapse="group.hideRows" class="collapse in" style="height: auto;">
<div class="data-row child-row ng-scope" ng-repeat="thing in filtered = (group.data | filter: filterStuff | filter: filterText | orderBy: getValueToOrderByChild() : sortingCriteria.descending)">
<div class="col-md-3 cell-data child-row-indent text-capitalize">
<span class="clickable-element ng-binding">CHILD ONE</span> <br>
</div>
<div class="col-md-2 child-row-indent-responsive">
<span class="visible-xs visible-sm">Status: </span><span class="ng-binding"> CHILD TWO </span>
</div>
</div>
</div>
And these are my statements to extract the text:
var headerText = element.all(by.repeater('group in tableData')).get(0).all(by.tagName('div')).get(0).element(by.css('div > strong')).getText();
var childOne = element.all(by.repeater('group in tableData')).get(0).all(by.tagName('div')).get(1).element(by.css('div > div:nth-child(1) > span').getText();
When I ran this, it returned a whole block of all the functions but not the actual text. Any help would be appreciated.
It is important to understand that WebdriverJS and protractor itself are entirely based on the concept of promises due to their asynchronous nature. See Promises and the Control Flow.
In other words, getText() in your case returns a promise. If you want to see the actual value, you need to resolve it:
headerText.then(function (text) {
console.log(text);
});
Note that you don't need to resolve promises inside an expect() - it knows how to resolve promises before making an expectation (thanks to jasminewd).

Categories

Resources