I have an array of items that a user selects from a dropdown and is saved to the db. The list of items are saved in an uppercase format. I'm looking to find an item from a db stream and return it in a 'friendly format'.
TS --
enumMap() {
const oldValue = this.rows.map(item => item.oldValue);
const savedItem = oldValue.find(element => element === 'SAVEDITEM');
if (savedItem) {
return 'Saved Item';
}
}
HTML -
<ngx-datatable-column name="Previously" prop="changedFrom" [minWidth]="50" [maxWidth]="150">
<ng-template ngx-datatable-cell-template let-rowIndex="rowIndex" let-value="value" let-row="row">
<span> {{row.oldValue}} </span>
</ng-template>
</ngx-datatable-column>
You can use regexes to do that along with a pipe.
But right now, you can't really.
SAVEDITEM has no delimitor and only a human (or a smart IA) would be able to do so.
Try saving it at least as SAVED_ITEM so that you know when to split it.
As for the pipe, the internal titlecase pipe should do the trick easily, no need to write a custom one.
Related
I have an array of objects that includes an element with an object and I'm looking to display the name of the object on a selectable dropdown using ng-select. I can console log everything as expected, however when I try to display the data I am only able to show [object, object]. The correct number of objects.
HTML -
<ng-select
[searchable]="false"
bindValue="id"
bindLabel="medications.items"
[items]="selected"
[(ngModel)]="serviceUsersMedication">
</ng-select>
TS -
onSelect({selected}) {
this.selected = selected;
const filteredMeds = this.selected.filter(item => {
return item.medications;
});
this.serviceUsersMedication = filteredMeds.map(item => {
return item.medications;
});
console.log('Selected:');
console.log(this.selected);
}
You're using the same variable for [items] (the collection ng-select uses to display the options) as for [(ngModel)] (used for storing/displaying the SELECTED (1) item).
You have to split this:
[items] should refer to the collection
[(ngModel]) should refer to your selected item.
Your ng-select should look like this:
<ng-select
[searchable]="false"
bindValue="id"
bindLabel="name"
[items]="medications.items"
[(ngModel)]="selected">
</ng-select>
Assuming you have a name attribute in the items array of medication, else change it to the attribute that makes sense to show.. selected is already containing the selected item, no need to filter for that.
Also assuming you're using ng-select from #ng-select/ng-select
In Angular, how to use *ngIf to check whether a JSON value includes a certain string, and then show them a certain URL ? In my case I have a object name called campaigns.description which has a value that includes a description. I want to see whether a given string, for example "one beam" is included in that description and show an URL based on that.
So not the way that the value equals a certain string, but the text that is held within the value includes a certain string.
You can use indexof() function to check the existence of some substring inside a string. This function returns '-1' if the substring is not present in the string.
<label *ngIf="campaigns.description.indexOf('One Beam') != -1 ? true : false">{{urlToShow}}</label>
You could generally use indexOf to check whether a string contains a sub-string.
console.log("Sample string".indexOf('string'));
console.log("Sample string".indexOf('not'));
The Angular part:
Trivial (not recommended)
Trivial solution is to check directly in the *ngIf condition
<div *ngIf="campaigns.description.indexOf('one beam') !== -1; else other">
<!-- contains the sub-string -->
</div>
<ng-template #other>
<!-- does not contain the sub-string -->
</ng-template>
However binding a function to *ngIf directive with default change detection strategy would trigger the function for each change detection cycle. It might lead to performance issues.
Additional property (recommended)
You could introduce additional property to hold the result of the condition in the controller and use it in the template.
Controller (*.ts)
// I assume `campaigns` is initialized in a subscription
ngOnInit() {
someObservable.subscription(
(res: any) => {
this.campaigns = {
...res,
subString: res.description.indexOf('one beam') !== -1
}
},
(error: any) => { }
);
}
Template (*.html)
<div *ngIf="campaigns?.subString; else other">
<!-- contains the sub-string -->
</div>
<ng-template #other>
<!-- does not contain the sub-string -->
</ng-template>
I've been learning jhipster for the past week now and I'm trying to implement a sortable table. I wanna ask how does the jhiSort and jhiSortBy work? I don't quite understand what does the predicate, ascending and callback function in jhiSort do. Also, which files do the id, date and amount in jhiSortBy come from and how does jhiSortBy work?
<tr jhiSort [(predicate)]="predicate" [(ascending)]="reverse" [callback]="transition.bind(this)">
<th jhiSortBy="id"><span>ID</span> <span class="fa fa-sort"></span></th>
<th jhiSortBy="date"><span>Date</span> <span class="fa fa-sort"></span></th>
<th jhiSortBy="amount"><span>Amount</span> <span class="fa fa-sort"></span></th>
</tr>
jhiSort and jhiSortBy are two directives provided by JHipster that help you implement sorting in data tables. You can see exactly what they do in the links I've provided.
jhiSortBy
The call you see in the header of each column just tells the jhiSortBy directive the name of the attribute it will sort the table by. In your case this means id, date and amount are all attributes of the entities being listed in your table.
This directive handles the user interaction and calls jhiSort to do the actual sorting, plus some extra steps to manage icon changes.
jhiSort
This directive has three properties:
#Input() predicate: string;
#Input() ascending: boolean;
#Input() callback: Function;
When you do [(predicate)]="predicate" you are telling angular that the predicate property of the jhiSort directive (left hand side of the assignment) will bind to a property in your component of the same name (right hand side). So in your *.component.ts you must have a property named predicate that will store the sorting information.
The directive has also a boolean property named ascending, when you do [(ascending)]="reverse" you are telling angular to bind the ascending directive property to a component property named reverse, just like before but this time the names don't match. This property controls only the sorting direction (ascending or descending).
Finally, callback is just the method that will be called on user interaction (click on a table header) to put everything in motion. transition is the name of such method in your *.component.ts, and it looks something like this:
transition(): void {
this.router.navigate(['./'], {
relativeTo: this.activatedRoute.parent,
queryParams: {
page: this.page,
sort: this.predicate + ',' + (this.ascending ? 'asc' : 'desc'),
},
});
}
This will force a navigation change so that the new order and page information persist on the URL, allowing future navigation events to get back without resetting the table.
This navigation change eventually calls loadAll() sending a query to your server-side with the new ordering (and paging) parameters.
The result of this query (a properly ordered list of entities) will be later sent back to the client-side to be displayed.
Very roughly this is how they work.
I is not working correctly:
I found the solution,
it is related to the method
fillComponentAttributesFromResponseBody
change the content of that method to be like this::
protected fillComponentAttributesFromResponseBody(data: IReferences[] | null): IReferences[] {
const referencesNew = [];
if (data) {
for (const d of data) {
if (referencesNew.map(op => op.id).indexOf(d.id) === -1) {
referencesNew.push(d);
}
}
}
return referencesNew;
}
and it will work.
enjoy
How can I access filteredArray in my .ts component? Because right now it is accessible only inside ng-container.
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<tr *ngFor="let user of filteredArray">
<td>{{user.name}}</td>
<td>{{user.group}}</td>
</tr>
<div>Count: {{ filteredArray.length }}</div>
</ng-container>
How can I modify the code in order to obtain what I want? Thank you for your time!
To answer your question directly: it's not possible the way you describe it. But read on.
Pipes (sometimes still called "filters") should be used only to format data, i.e. prepare it in a human-readable form. For example, the build-in date pipe can be used to transform an ISO string to a string such as "March 21st, 1995", which is how a human from the USA might expect to read the date.
The way you're using pipes is not recommended, precisely because of the question you have. You've essentially put application logic inside a template, which is an anti-pattern and beats the purpose of having easy-to-read declarative templates, which Angular uses in order to figure out how to update DOM.
You should move the filtering logic back to the class. For example, instead of setting this.userList = xxx, you could have a function which you call every time, such as this.changeUserList(xxx).
changeUserList (list) {
this.userList = list
this.filteredArray = list.filter(...)
}
You can put this logic in a setter as well, which allows you to run custom code when you write the usual this.userList = list, but you'll need a separate (usually prefixed private) property on the class where you'd actually store the value. It's not really a limitation since you can also have a trivial getter, so you can still us this.userList normally as a getter without having to remember to use this._userList, essentially tucking this away as the get/set pair's implementation detail.
private _userList
public set userList (list) {
this._userList = list
this.filteredArray = list.filter(...)
}
public get userList (list) { return this._userList }
Observables could really come in handy here as well, since you could just rx.map the userList$ to filteredArray$ with an Array#filter.
public userList$
public filteredArray$ = this.userList$.pipe(map(arr => arr.filter(...))
Then in the template, you can use the async pipe.
*ngIf="filteredArray$ | async as filteredArray"
Avoid doing the following.... but it works for demo purposes 😃
Create a component (e.g. demo-element.component.ts) that takes a single #Input() value:any
Add this new component as the first child of the <ng-container>, and give it a template reference #containerRef e.g.:
<ng-container *ngIf="(userList | filter: 'name' : value) as filteredArray">
<demo-element #containerRef [value]="filteredArray"></demo-element>
In your main component, add
#ViewChild('containerRef') ref;
ngAfterViewInit() {
this.filteredArray = this.ref.value; // Terrible pattern, but answers the question:-)
}
I hope this below code will help you.
<div class="rsrvtn_blk" *ngIf="(items | fSearch:firstname) as filteredItems">
<div class="col-md-3 pl-0" *ngFor="let item of filteredItems">
// you can display the filtered content here
</div>
</div>
I have created a form which allows the user to add additional text-inputs by clicking a button. The FormControls behind these inputs are stored in a FormArray inside of a FormGroup.
I want to provide a default value for these inputs, that is going to be submitted if they are pristine. If the user changes the value of the input, which changes it to dirty, I do not want the default value to be submitted or displayed.
I currently am displaying the inputs like this, as the placeholder attribute does exactly what I want, displaying the default name, only if the input has not been changed.
<div
formArrayName="names"
*ngFor="let server of names.controls; let i = index; trackBy:trackByFn">
<span>{{ i + 1 }}</span>
<input
type="text"
formControlName="{{i}}"
placeholder="{{defaultName}}">
</div>
To validate the names I have created the following validation function:
export function validateServerName(form: FormGroup): ValidationErrors | null {
const names: string[] = form.value[CREATE_FORM_KEY_NAMES];
for (const name of names) {
if (name.trim() === '') {
return {
invalidName: true
};
}
}
return null;
}
Here I am having trouble figuring out if the element is dirty or pristine, as form.value[key] only returns a string array, not an array of the FormControls.
I am looking for either an easier way to do what I am trying to achieve, or a way to validate the form properly.
you can check the control status using
if touched is true then its dirty
this.form.get('controlname').touched
and for pristine you can check like
this.form.get('controlname').pristine
UPDATE
for form array it will be something like
let val = this.user.get('<FormArray>') as FormArray;
console.log(val.at(index));
you can now use pristine and touched on this variable