I'm working on a list of values in my web-app. There I'm facing the following problem:
app.component.html
This part of the code shows my array as a list:
<div class="body__tags">
<ng-container *ngFor="let tag of tags; let i=index">
<li class="tags__list" *ngIf="i<5" [label]="tag"></li>
</ng-container>
</div>
Here I set limit of 5 values in my list. But sometimes there are more than 5 values in the array. How can I add a button "show all" and then display everything in that list?
app.component.ts
This is my ts code:
tags:any[];
splitTags() {
if (this.data.tags != null) {
this.tags = this.data.tags.split(";");
console.log(this.tags)
}
}
ngOnInit() {
this.splitTags()
}
Using *ngIf is not the best idea for such scenario.
You should slice the array upto 5 and store into another variable.
once User clicks on the button to show all the data, assign the entire array to the new variable.
for Example :
this.data = [1,2,3,4,5,6,7,8,9,10];
this.newData = data.slice(0,5);
then in the component.html file : ;
<div class="body__tags">
<ng-container *ngFor="let tag of newData; let i=index">
<li class="tags__list" [label]="tag"></li>
</ng-container>
</div>
on button click you should assign entire data to newData variable.
public showAll(){
this.newData = this.data;
}
Working demo
you can keep 5 in some variable and then on click of 'ShowAll()' you can increase the limit
Related
I have an array of countries and i want to display in a mat-select list of options. I am receiving the data like an object format in this.lngCountries so i need to convert to array first.
I think that the array is not complete before the ngfor is loaded. How can I wait for my function to finish? Because my problem is that when the page loads the ngfor my array is still empty.
My code:
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
}
HTML:
<th2-mat-select class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Thanks!!! <3
One way is ngIf
<th2-mat-select *ngIf="paisOps && paisOps.length > 0" class="form-field-dark" required [form]="usecaseForm"
formControlFieldName="pais"
placeholder="País">
<mat-option *ngFor="let country of paisOps" [value]="country">{{country}}</mat-option>
</th2-mat-select>
Better is to show a loading spinner instead of the select as example for a better user experience.
You can set a custom variable, too:
loading: boolean = true;
...
private preparePaisOpts() {
let array = this.lngCountries;
this.paisOps = Object.keys(array).map(function(index) {
let count = array[index];
return count;
});
this.loading = false;
}
and HTML
<th2-mat-select *ngIf="!loading" class="form-field-dark" .......
But!
Normally ngFor will be refresh the data if it's array changing. You write not specific error so I don't know what your problem is.
I am having a drop down list where user can select multiple items from it, and items will be appended the into an array selectedInvoicesArray:
Object.keys(selectedInvoices).forEach((key, index)=>{
this.selectedInvoicesArray.push(this.invoicesList.filter(res => {
return res.invoice_id == selectedInvoices[key]
}));
})
At the html side, we have a *ngFor to loop over selectedInvoicesArray array and display info of each index into a div.
What I need is to display a drop down list having Active and Inactive as options, where the original value is selected once the section of each item is displayed on the component, and then user can change the status.
The only method to do that is by using FormArray.
So I did the following:
I created a form group containing a form array:
<form [formGroup]="updateStatusForm">
<mat-form-field *ngFor="let select of selectedInvoicesArray; let i = index">
<mat-select [formControlName]="i">
<mat-option *ngFor="let status of invoiceStatuses" [value]="status.id">{{status.name}}</mat-option>
</mat-select>
</mat-form-field>
</form>
Then, I created the formGroup script:
updateStatusForm: FormGroup;
createUpdateStatusForm(){
this.updateStatusForm = this.fb.group({
'statusesControl': new FormControl('')
})
}
And I called createUpdateStatusForm() each time a new array is being pushed into selectedInvoicesArray:
Object.keys(selectedInvoices).forEach((key, index)=>{
this.selectedInvoicesArray.push(this.invoicesList.filter(res => {
return res.invoice_id == selectedInvoices[key]
}));
this.createUpdateStatusForm()
})
As you can see in the image, the drop down list is empty. I need to set it to the initial value coming from the array.
The *ngFor that is iterating over selectedInvoicesArray is as follows:
<div *ngFor="let invoice of selectedInvoicesArray;let i = index;">
And as an example:
<div>
Description: {{invoice[0].description}}
</div>
When I push 2 or more arrays into selectedInvoicesArray, in each section I see 2 or more drop down lists:
But I am not able to set the initial value of each generated form array to display the original status coming with the array which named is_active.
EDIT
What I tried next, is to loop over selectedInvoicesArray and set the value of each generated form array:
Object.keys(this.selectedInvoicesArray).forEach(key=>{
console.log(this.selectedInvoicesArray[key].invoices[0])
this.createUpdateStatusForm(this.selectedInvoicesArray[key].invoices[0].is_active);
})
And:
createUpdateStatusForm(status_id){
this.updateStatusForm = this.fb.group({
'statusesControl': new FormControl(status_id)
})
}
But I've got the following error:
Cannot read property 'get' of undefined
at FormGroupDirective.addControl
In an Index-gsp, I want to be able to select an arbitrary number of lines and then by clicking a link send all those lines to a controller for processing e.g. creating new objects of a different kind.
I've no idea how selection can be done or how to collect these selected lines in a GSP. Maybe I should use a checkbox on each line if that's possible?
It's a list of products which is displayed using a modified index.gsp.
Each product-line has a checkbox in front.
What I want is to make a list of the products that are checked an then transmit this list to a controller.
a part of this index.gsp:
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
<li><g:link class="create" action="createOffer"><g:message code="default.new.label" args="[entityName]" params="toOffer" /></g:link></li>
</ul>
</div>
<div id="list-prodBuffer" class="content scaffold-list" role="main">
<h1><g:message code="default.list.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<table>
<thead>
<tr>
<td> Välj</td>
<td> ID</td>
</tr>
</thead>
<tbody>
<g:each in="${prodBufferList}" status="i" var="prodBuffer">
<tr class="${ (i % 2) == 0 ? 'even': 'odd'}">
<td><g:checkBox name="toOffer" value="${prodBuffer.id}" checked="false" /></td>
<td>${prodBuffer.id}</td>
So this not an ordinary form, just a list where I want to use a link to transmit it to the controller.
I'm a beginner and have no idea how to do it.
You can collect all necessary data from page using javascript, and then send all data to your controller for processing.
There are a lot of ways to do it.
For example send via JQuery:
<script>
//some code
var items = [1,2,3];
//some code
$('#add-location').click(function () {
$.ajax({
type: "POST",
url: "${g.createLink(controller:'myController', action: 'myControllerMethod')}",
data: {items: items},
success: function (data) {
console.log(data)
}
});
});
</script>
I will answer this but have to slow down since it feels like i am beginning to write your project:
In gsp you will need to have a hidden field followed by a check box amongst data you are trying to capture, checkbox should contain all the data elements required to build your output.
<g:hiddenField name="userSelection" value=""/>
<g:checkBox name="myCheckBox" id='myCheckBox' value="${instance.id}"
data-field1="${instance.field1}" data-field1="${instance.field1}"
checked="${instance.userSelected?.contains(instance.id)?true:false}" />
In the java script segment of the page you will need to add the following
This will then auto select selection and add to javascript array
// Customized collection of elements used by both selection and search form
$.fn.serializeObject = function() {
if ($("[name='myCheckBox']:checked").size()>0) {
var data=[]
$("[name='myCheckBox']:checked").each(function() {
var field1=$(this).data('field1');
var field2=$(this).data('field2');
data.push({id: this.value, field1:field1, field2:field2 });
});
return data
}
};
Most importantly will your data sit across many different gsp listing pages if so you will need to hack pagination:
//Modify pagination now to capture
$(".pagination a").click(function() {
var currentUrl=$(this).attr('href');
var parsedUrl=$(this).attr('href', currentUrl.replace(/\&userSelection=.*&/, '&').replace(/\&userSelection=\&/, '&'));
var newUrl=parsedUrl.attr('href') + '&userSelection=' + encodeURIComponent($('#userSelection').val());
window.location.href=newUrl
return false;
});
Then in the controller parse the JSON form field and make it into what you want when posted
def u=[]
def m=[:]
if (params.userSelection) {
def item=JSON.parse(params.userSelection)
item?.each {JSONObject i->
// When field1 is null in JSON set it as null properly
if (JSONObject.NULL.equals(i.field1)) {
i.field1=null
}
if (resultsGroup) {
if (!resultsGroup.contains(i.id as Long)) {
u << i
}
} else {
u << i
}
}
m.userSelected=item?.collect{it.id as Long}
m.results=u
}
return m
I have a grid with checkbox, I am putting checked values in an array (currentFocusedRow), now I want to assign activeRow class to the checked row:
// app.ts
class contact {
public contactlist = [{icontact_id: "contact1"}, {icontact_id: "contact2"}, {icontact_id: "contact3"}, {...}];
public currentFocusedRow = ["contact2", "contact3"];
}
// app.html
<tr *ngFor="let contact of contactlist"
[class.activeRow]="contact.icontact_id == currentFocusedRow">
...
</tr>
now since currentFocusedRow is an array i can't simply check like that (contact.icontact_id == currentFocusedRow) there should be something to check if the value is present in that array or not like indexOf.
I think this should work for you:
Typescript
isActive(id) {
return this.currentFocusedRow.indexOf(id) !== -1
}
HTML
<tr *ngFor="let contact of contactlist"
[class.activeRow]="isActive(contact.icontact_id)">
</tr>
You can use index of the object that is current object, by using:
<tr *ngFor="let contact of contactlist; let i = index">
Which will enable you to get those indexes.
Apart from that, you can just use NgClass directive.
Checking with indexOf in directive itself worked, this is pretty amazing that we can use this JS methods directly in DOM:
<tr *ngFor="let contact of contactlist;"
[class.activeRow]="currentFocusedRow.indexOf(contact.icontact_id) != '-1'">
</tr>
I have array of object say person which have two property name and hideMe. i have make a directive to add, remove person from array and use filter to hide the person using property hideMe.
service
app.factory("personService", function () {
var person = function () {
this.name = "";
this.hideMe = false;
};
var persons = [];
return {
add: function () {
persons.push(new person());
},
hide: function (index) {
persons[index].hideMe = true;
}
}
});
controller
app.controller("personCtrl", function ($scope, personService) {
$scope.model = personService;
});
HTML
Add New Person
<table>
<tr>
<td>Name </td>
<td>remove</td>
</tr>
<tr ng-repeat="person in model.persons | filter : { hideMe: false}" >
<td>
<input type="text" ng-model="person.name">
</td>
<td>Hide Me </td>
</tr>
</table>
when i hide the person by click on hideMe link some time it is not hide ????
here is the fiddle http://jsbin.com/kolaraliki/1/
The reason you are experiencing this error is because of the use of $index.
$index gives the index of the current item in the iterator ng-repeat, not the index of the source element. As soon as an item is removed from the array, the $digest triggers the ng-repeat to re-calculate, and $index of the items in the ng-repeat are re-calculated. Thus, if you have 3 items in your array, at 0,1,2 but item 1 is hidden, you would expect your ng-repeat would have 2 items, 0,2 but it actually has 0,1. clicking to hide 2 would actually try to hide 1 in the array, which is already hidden.
instead of using $index, try instead model.hide(model.persons.indexOf(person)) to get the actual array index instead of the iterator index.
I forked your jsbin with an example: http://jsbin.com/jecosofequ/2/edit
It is because you have already filtered only those persons who have hideMe value as true to be shown and by clicking link which calls hide() you are simply setting hideMe value as true for second time. You can simply fix this by changing that filter to be filter: { hideMe: false } in your ngRepeat and then it should work. Because it would show's only those objects which hideMe values are false.