when i push select2OptionData object in an array, select2 don't display any value - arrays

select2 in my angular project. I want to display a select of an array of certificate requested from an api. For each element if I create and push a select2OptionData Object in an array, but when i want to display it in the Html page it is selected but without any option. When i create an array of object like the gitHub demo everything's right.
Can you help me please.
Here is the ts
export class DashboardCvComponent implements OnInit, OnDestroy {
certificateForm: FormGroup;
certificates: Array<Certificate>;
certificatesTypes: Array<Select2OptionData>;
exampleData: Array<Select2OptionData>;
constructor(private formBuilder: FormBuilder, private certificatesService: CertificatesService,
private trainingsService: TrainingsService, private authService: AuthenticationService,
private datepipe: DateFormatPipe, private CvService: CVService, private fileUploaService: FileUploadService) {
this.certificatesTypes = [];
this.exampleData = [];
}
ngOnInit() {
// get certificate types
this.certificatesService.getAllCertificatesType('50').subscribe(
(response) => {
// console.log('-> CERTIFICATES TYPES LOADING successful : ', response);
/* this.certificatesTypes = response.data; */
response.data.forEach(element => {
const certif = {id: element.id.toString(), text: element.name};
this.certificatesTypes.push(certif);
});
this.exampleData = [{
id: 'basic1',
text: 'Basic 1'
},
{
id: 'basic2',
disabled: true,
text: 'Basic 2'
},
{
id: 'basic3',
text: 'Basic 3'
},
{
id: 'basic4',
text: 'Basic 4'
}]
console.log('les certif', this.exampleData, this.certificatesTypes);
},
(error) => {
console.log('-> CERTIFICATES TYPES LOADING failed : ', error);
},
() => {
}
);
and the html
<div class="dashboard--degrees">
<app-certificate *ngFor="let certificate of certificates" [certificate]=certificate [url]=url></app-certificate>
<button class="button button--bluegreen" type="button" data-modal="modal-certificate">
<svg class="icon icon-plus-o">
<use xlink:href="#icon-plus-o"></use>
</svg> <span i18n="##cvcomponent-addcertificate">J'ajoute un diplôme </span>
</button>
<select2 [data]="certificatesTypes"></select2>
<select2 [data]="exampleData"></select2>
</div>
Here the exampleData select display well but not the certificatesTypes

Don't use this.certificate.push inside for loop. it will not work. instead of you can use something like :
let arrCertificates = [];
response.data.forEach(element => {
const certif = {id: element.id.toString(), text: element.name};
arrCertificates.push(certif);
});
this.certificatesTypes = arrCertificates;

Related

In a Salesforce LWC app how can I add checkbox values to an object's field and show it in a data-table?

I have made my research, but couldn't find the answer.
I have a Lightning App in Salesforce, I used LWC Js and Apex.
In one part of the app the user can add a 'desk item' (by typing its name) and select from a checkbox 1-2 items to add them to the 'desk'.
I used Apex to transfer the value of the 'desk item' to an Object and I can show it in a list (in the app).
How can I add the checkbox value(s) to the submitDesk(){...} so it sends its value(s) along with the 'desk item' value?
I don' know where/how exactly to add and to get it back?
The JS Code
import { LightningElement, track } from 'lwc';
import createDesk from '#salesforce/apex/FlexOfficeController.createDesk';
import getDesks from '#salesforce/apex/FlexOfficeController.getDesks';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class DeskList extends LightningElement {
// Desk
#track data_desks = [];
//table to show the desks's Id + Name, and the checkbox
columns = [
{ label: 'Id', fieldName: 'Id', type: 'text' },
{ label: 'Name', fieldName: 'Name', type: 'text' },
{ label: 'Accessories', fieldName: **the checkbox value**, type: 'text' }
];
// value to the picklist
connectedCallback(){
this.retreiveDesk();
}
retreiveDesk(){
getDesks({})
.then(d => {
this.data_desks = JSON.parse(d);
})
}
desk = {};
changeValue(event){
this.desk[event.target.name] = event.target.value
}
submitDesk(){
console.log(this.desk, this.value + 'Hi there');
createDesk({desk:JSON.stringify(this.desk)})
.then(data=> {
console.log(data + 'hello');
this.retreiveDesk();
// toaster
const evt = new ShowToastEvent({
title: "New desk",
message: `succefully created. Check out your reservation.`,
variant: "success"
})
this.dispatchEvent(evt);
})
}
// Checkbox
value = [];
get options() {
return [
{ label: 'Mouse', value: 'mouse' },
{ label: 'Screen', value: 'screen' },
];
}
// put the checkbox values into a string ('join')
get checkboxValues() {
console.log(this.value);
return this.value.join(',');
}
handleCheckboxChange(event) {
this.value = event.detail.value;
}
}
Apex Controller
public class FlexOfficeController {
#AuraEnabled
public static string createDesk(String desk){
try {
Desk__c d = (Desk__c)JSON.deserialize(desk, Desk__c.class);
insert d;
return d.id;
} catch (Exception e) {
throw new AuraHandledException(e.getMessage());
}
}
#AuraEnabled
public static string getDesks(){
try {
List<Desk__c> desks = new List<Desk__c> ();
desks = [SELECT Id, Name FROM Desk__c];
return JSON.serialize(desks);
} catch (Exception e) {
throw new AuraHandledException(e.getMessage());
}
}
}
HTML
<template>
<lightning-card>
<div class="slds-m-around_medium slds-theme_alert-texture">
<lightning-input name="Name" label="Name your desk" onchange={changeValue}></lightning-input>
<lightning-checkbox-group name="Accessories" label="Checkbox Group" options={options} value={value}
onchange={handleCheckboxChange}></lightning-checkbox-group>
<p>{checkboxValues}</p>
<lightning-button onclick={submitDesk} label="Submit"></lightning-button>
<lightning-datatable key-field="id" data={data_desks} columns={columns} hide-checkbox-column></lightning-datatable>
</div>
</lightning-card>
</template>

Refresh Datatable in for:each loop: Lightning Web Components

I am having trouble refreshing a Datatable in my Lightning Web Component after updating a record. I am calling an onclick action on a button within the row, and imperatively calling an Apex method to update that record. I then call the refreshApex() to update the data being fed into the Datatable.
However, after the refreshApex(), the tables within the for:each are not being refreshed with new data.
The records are properly modified and reflect the changes properly when refreshing the entire page.
Note: The Task object is not supported in LWC, and I cannot use the updateRecord() method to update these records.
HTML:
<template>
<template if:true="{taskCompWrapperList}">
<!--<lightning-layout multiple-rows="false" pull-to-boundary="small">-->
<template for:each="{taskCompWrapperList}" for:item="taskTemplate">
<lightning-layout-item
key="{taskTemplate.taskSectionOrder}"
size="3"
class="slds-p-around_x-small"
>
<!-- Start bear tile -->
<lightning-card title="{taskTemplate.taskSectionTitle}">
<div class="slds-m-around_medium">
<template if:true="{taskTemplate.taskList}">
<lightning-datatable
key-field="Id"
data="{taskTemplate.taskList}"
onrowaction="{handleRowAction}"
columns="{columns}"
onsave="{handleSave}"
draft-values="{draftValues}"
>
</lightning-datatable>
</template>
<template if:true="{contact.error}">
<!-- handle Apex error -->
</template>
</div>
</lightning-card>
<!-- End bear tile -->
</lightning-layout-item>
</template>
<!--</lightning-layout>-->
</template>
</template>
Javascript:
import { LightningElement, api, wire ,track} from 'lwc';
import getTaskCompWrappers from '#salesforce/apex/ENT_Task_Utility.getTaskComponentWrapper';
import updateTask from '#salesforce/apex/ENT_Task_Utility.updateTask';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '#salesforce/apex';
const COLS = [
{
type: 'button',
label: 'Complete',
typeAttributes:
{
//iconName: 'action:preview',
label: 'Complete',
name: 'Complete',
title: 'Complete',
value: 'Complete',
variant: 'brand',
alternativeText: 'Complete'
}
},
{
type: 'button-icon',
label: 'Start',
typeAttributes:
{
iconName: 'action:approval',
//label: 'Complete',
name: 'Start',
title: 'Start',
value: 'Start',
variant: 'success',
alternativeText: 'Start',
}
},
{
type: "button",
typeAttributes:
{
label: 'View',
name: 'View',
title: 'View',
disabled: false,
value: 'view',
iconPosition: 'left'
}
},
{
type: "button",
typeAttributes:
{
label: 'Edit',
name: 'Edit',
title: 'Edit',
disabled: false,
value: 'edit',
iconPosition: 'left'
}
},
//{ label: 'Complete', fieldName: 'Task_Complete__c', editable: true },
{ label: 'Status', fieldName: 'Status', type: 'picklist', editable: true },
{ label: 'Completed', fieldName: 'Completed', type: 'boolean', editable: true },
{ label: 'Owner', fieldName: 'OwnerId', editable: true },
{ label: 'Subject', fieldName: 'Subject' },
{ label: 'Due Date', fieldName: 'ActivityDate', type: 'date' }
];
export default class ENT_Task_Utility_LWC extends LightningElement {
#api objApiName;
#api recordId;
#track testMessage = 'Test Failed :c';
#track error;
#track columns = COLS;
#track draftValues = [];
taskCompWrapperList;
#track error;
//#wire(getTasks, {recordId: '$recordId'}) taskList;`
#wire(getTaskCompWrappers, {recordId: '$recordId', objApiName: '$objApiName'})
taskCompWrapperListWire({ error, data }) {
if (data) {
this.taskCompWrapperList = data;
this.error = undefined;
} else if (error) {
this.error = error;
this.taskCompWrapperList = undefined;
}
}
updateTaskValues (taskId, taskStatus) {
// eslint-disable-next-line no-console
console.log('updateTaskValues hit');
for(var counter = 0; counter < this.taskCompWrapperList.length; counter++) {
// eslint-disable-next-line no-console
console.log('taskWrapper: ' + this.taskCompWrapperList[counter]);
for(var counter2 = 0; counter2 < this.taskCompWrapperList[counter].taskList.length; counter2++) {
// eslint-disable-next-line no-console
console.log('task: ' + this.taskCompWrapperList[counter].taskList[counter2]);
if(this.taskCompWrapperList[counter].taskList[counter2].Id == taskId)
{
this.dispatchEvent(
new ShowToastEvent({
title: 'Task Id Found!',
message: this.taskCompWrapperList[counter].taskList[counter2].Id,
variant: 'success'
})
);
this.taskCompWrapperList[counter].taskList[counter2].Status = taskStatus;
}
}
}
}
handleRowAction(event) {
//TODO
}
}
Apex methods:
#AuraEnabled(cacheable=true)
global static List<Task> getTasks(String recordId)
{
return [SELECT Id, Subject, OwnerId FROM Task WHERE WhatId = :recordId];
}
#AuraEnabled(cacheable=true)
global static List<ENT_Task_Comp_Wrapper> getTaskComponentWrapper(String recordId, String objApiName)
{
List<Task_Template__c> taskTemplateList = [SELECT Id, Task_Component_Section_Order__c, Task_Component_Section_Title__c, (SELECT Id FROM Task_Template_Items__r)
FROM Task_Template__c
WHERE Active__c = true AND sObject__c = :objApiName ORDER BY Task_Component_Section_Order__c ASC];
List<Task> taskList = [SELECT Id, Task_Template_Item__c, OwnerId, Owner.Name, Subject, Description, Status, ActivityDate, Task_Complete__c FROM TasK WHERE WhatId = :recordId];
List<ENT_Task_Comp_Wrapper> taskCompWrapperList = new List<ENT_Task_Comp_Wrapper>();
for(Task_Template__c taskTemplate : taskTemplateList)
{
ENT_Task_Comp_Wrapper taskCompWrapper = new ENT_Task_Comp_Wrapper();
taskCompWrapper.taskSectionTitle = taskTemplate.Task_Component_Section_Title__c;
taskCompWrapper.taskSectionOrder = (Integer)taskTemplate.Task_Component_Section_Order__c;
taskCompWrapper.taskList = new List<Task>();
for(Task currentTask : taskList)
{
for(Task_Template_Item__c taskTemplateItem : taskTemplate.Task_Template_Items__r)
{
if(taskTemplateItem.Id == currentTask.Task_Template_Item__c)
{
taskCompWrapper.taskList.add(currentTask);
}
}
}
taskCompWrapperList.add(taskCompWrapper);
}
System.debug(taskCompWrapperList);
return taskCompWrapperList;
}
#AuraEnabled
global static void updateTask(String taskId, String newStatus)
{
System.debug(taskId);
Task taskToUpdate = new Task(Id = taskId, Status = newStatus);
update taskToUpdate;
//update taskToUpdate;
}
#AuraEnabled
global static void updateTask(String taskId, String newStatus)
{
System.debug(taskId);
Task taskToUpdate = new Task(Id = taskId, Status = newStatus);
update taskToUpdate;
//update taskToUpdate;
}
In your JS code you have imported refreshApex
by using this line import { refreshApex } from '#salesforce/apex';
but you didn't assigned to any wire method. Hence data is not refreshed
Please refer this documentation.
To refresh a wired method, pass the argument the wired method receives (which is the wired value) to refreshApex(). In this sample code, the wired method is taskCompWrapperListWire. Hold on to the value provisioned by the wire service and pass it to refreshApex().
#wire(getTaskCompWrappers, {recordId: '$recordId', objApiName: '$objApiName'})
taskCompWrapperListWire({ error, data }) {
if (data) {
this.taskCompWrapperList = data;
this.error = undefined;
} else if (error) {
this.error = error;
this.taskCompWrapperList = undefined;
}
}
And then use refreshApex() as below:
refreshApex(this.taskCompWrapperListWire);
Update you code as below
updateTaskValues({
taskId: this.taskId,
taskStatus: this. taskStatus
})
.then(() => {
// your code logic
refreshApex(this.taskCompWrapperListWire);
})
.catch((error) => {
this.message = 'Error received: code' + error.errorCode + ', ' +
'message ' + error.body.message;
});
you probably need to wait for next release to have a correct way to handle such situation.
You are getting record through uiRecordApi and updating through Apex if I'm correct.
Then you would need to use getRecordNotifyChange() available in Winter 21 release.
Apart from the answer provided by Sudarshan, you should also define taskCompWrapperList as a reactive property to make it rerender when the property is updated.
#track taskCompWrapperList = [];

Angular 5 - JSON to "scope" binding to *NgFor

I want to bind the data that i get from my JSON request to the *NgFor to be able to read it out, This is how the data looks like that i get in:
{Id: null, Code: "9348892084", HasInfo: true, Info: Array(26)}
HasInfo:true
Info:
Array(26)
0:{ProductId: 32631, Name: "JNOOS", Image: "http://sd-m-mg", …}
1:{ProductId: 32969, Name: "SWIFT", Image: "http://sd-33087.jpg",…}
2:{ProductId: 32570, Name: "GABIX", Image: "http://sd-c7273.jpg", …}
3:{ProductId: 32473, Name: "MISMA", Image: "http://sd-mt8-8343e4d95.jpg", …}
I was working with AngularJS before and there i made the request as such:
$scope.getAll{
$http({
method: 'Get',
url: "http://URL/" + Code
})
.success(function (data) {
$scope.All = data.Info;
})
No i am moving to Angular5 and i would like to get the same array of information bind to the :
<div *ngFor="let x of info">
{{ x.Name }}
</div>
How would i adjust the below to get the same as above?
export class AppComponent {
readonly ROOT_URL = 'http://url/content/'
constructor(private http: HttpClient) {}
ngOnInit() {
this.getData()
}
getData() {
this.http.get(this.ROOT_URL + 'Getscope')
.subscribe(
data => {
var test = data;
// var info = data.Info = not valid!;
// var test can't be approached by *ngFor
console.log(test);
console.log(test.info);
//$scope.info = data.Info;
//this.info = data;
}, error => {
console.error("HTTP FAILURE ERROR!!!");
}
)
};
}
Also the json output has an array inside an object, do i say this correct?
From your code you are using info in html but not assigning to any class variable,
Take a public variable public info; and assign data using this.info = data.Info
Component:
export class AppComponent {
readonly ROOT_URL = 'http://url/content/'
public info;
constructor(private http: HttpClient) {}
ngOnInit() {
this.getData()
}
getData() {
this.http.get(this.ROOT_URL + 'Getscope')
.subscribe(
data => {
this.info = data['Info']; // here is the change
}, error => {
console.error("HTTP FAILURE ERROR!!!");
}
)
};
}
Your HTML can be same:
<div *ngFor="let x of info">
{{ x.Name }}
</div>
The simplest solution would be to use an async pipe. This way you do not need to subscribe to the stream returned by http.get.
app.component.ts
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
export class AppComponent {
readonly url = 'http://url/content/'
constructor(private http: HttpClient) {}
info$: Observable<any[]>;
ngOnInit() {
this.info$ = this.http.get(this.url + 'Getscope')
.pipe(map(resp => resp.Info));
}
}
app.component.html
<div *ngFor="let x of info$ | async">
{{ x.Name }}
</div>

Change detection running infinitely when function is used with ngIf

I am working on an Ionic 2 project. The template has a ngIf to check if its the right user.
show.ts
constructor( public book: Bookemon ){}
rightUser(){
console.log('right user');
return this.book.rightUser(this.hunt.user.id);
}
bookemon.ts (bookemon and auth are services )
rightUser(id: number){
return this.auth.user.id === id;
}
show.html
<ion-content fullscreen="true">
<div id="image-modal" >
<img [src]="imageSource(hunt.picture_url)" (click)="dismissModal()" >
<button ion-fab mini *ngIf = " !hunt.picture_url " (click)="showEditHuntModal()" color="ionic">
<ion-icon name="add" ></ion-icon>
</button>
<button color="danger" class="new-claim" ion-button round icon-left *ngIf = "rightUser() && hunt.claims.length " (click)="openClaimModal(hunt)">
<ion-icon name="trophy"></ion-icon>
New Claim
</button>
</div>
<div class="hunt-content">
<button small clear ion-button icon-only class="options" *ngIf="rightUser()" (click)="presentAction()">
<ion-icon name="md-more"></ion-icon>
</button>
<hunt [hunt]="hunt" [huntedUser]="huntedUser" ></hunt>
</div>
<ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('rejected')" class="close-fab">
<button ion-fab color="danger" ><ion-icon name="close" ></ion-icon></button>
</ion-fab>
<ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('accepted')" class="heart-fab">
<button ion-fab color="primary" ><ion-icon name="heart" ></ion-icon></button>
</ion-fab>
</ion-content>
The template displays some content based on *ngIf = "rightUser()"
Everything works fine except , the console is logged with infinitely many right user which comes from rightUser() function. The expected behaviour should be right user logged once in console and no more change detection being run.
Is it a bad practice to use functions in ngIf ? What is triggering change detection infinite times here?
Edit
I tried a function with ngIf in a fresh project and it doesnt run change detection infinite times. I am not sure whats causing it here. Here is my show.ts in case that helps.
export class ShowPage {
hunt: Hunt ;
huntedUser: User;
editHuntPage= EditHuntPage;
claimHuntPage = ClaimHuntPage;
rightUser: Boolean;
constructor(public alert: AlertController , public modal: ModalController, public events: Events
, public toastCtrl: ToastController, private navParams: NavParams , public action: ActionSheetController
, public book: Bookemon , public viewCtrl: ViewController, public nav: NavController) {
console.log(navParams.data);
this.hunt = navParams.data.hunt;
this.rightUser = this.book.rightUser(this.hunt.id);
}
ionViewDidLoad(){
console.log('view');
if(this.hunt.status == "hunted"){
this .book.getHuntedUser(this.hunt).subscribe( (res) => {
this.huntedUser = res.json();
console.log(this.huntedUser);
})
}
}
imageSource(pic: string){
return pic ? pic : CONFIG.noHuntPic ;
}
dismissModal(status?: string){
console.log('dismiss');
this.viewCtrl.dismiss(status);
}
presentAction(){
let actionSheet = this.action.create(
{
title: this.hunt.title ,
buttons: [
{
text: 'Edit',
handler: () => {
let trans = actionSheet.dismiss();
trans.then( () => {
this.showEditHuntModal();
})
return false;
}
},
{
text: 'Delete',
role: 'destructive',
handler: () => {
let trans = actionSheet.dismiss();
trans.then( () => {
this.deleteAlert();
})
return false;
}
},
{
text: 'Cancel',
role: 'cancel',
}
]
})
actionSheet.present();
}
showEditHuntModal(){
let modal = this.modal.create(EditHuntPage,this.hunt);
modal.present();
modal.onDidDismiss( (data) => {
if(data){
this.hunt = data;
}
})
}
deleteAlert(){
let alert = this.alert.create({
title: 'Confirm',
message: 'Do you want to delete this hunt?',
buttons: [{
text: "Delete",
handler: () => { this.deleteHunt() }
}, {
text: "Cancel",
role: 'cancel'
}]
})
alert.present();
}
deleteHunt(){
this.book.deleteHunt(this.hunt.id).subscribe( (res) => {
// this.events.publish("user-hunts:deleted",this.hunt);
this.viewCtrl.dismiss("deleted",this.hunt);
}, (err) => {
this.handleError(err);
})
}
openClaimModal(hunt){
let claimModal = this.modal.create(ShowClaimPage,{hunt: hunt})
claimModal.present();
}
rightUser(){
console.log('right user');
return this.book.rightUser(this.hunt.user.id);
}
handleError(err){
console.log(err);
let error= err.message ? err.message : "Error occured";
let toast = this.toastCtrl.create({ message: error, duration: 2000 , position: 'top'});
toast.present();
}
}
angular uses zones.js to detect if something changes in your app so it will check ngIf each time, you can this something like this :
<button small clear ion-button icon-only class="options" *ngIf="isRightUser" (click)="presentAction()">
<ion-icon name="md-more"></ion-icon>
</button>
//...
<button small clear ion-button icon-only class="options" *ngIf="isRightUser" (click)="presentAction()">
//show.ts
isRightUser:boolean;
constructor( public book: Bookemon ){}
ngOnInit(){
this.isRightUser= rightUser();
}
rightUser(){
return this.book.rightUser(this.hunt.user.id);
}

Highchart TypeScript using Angular

I'm getting stuck to save const variable data using Highcharts, TypeScript and Angular1.5.
This works though, doesn't show up each data.
Does anyone have any ideas to solve this?
Any suggestions would be appreciated.
Thank you so much,
Takahiro
class MSSPiesController {
private chartData:{
availability?:IPieData//data type
itemType?:IPieData//data type
linkOwner?:IPieData//data type
} = {};
public chartTest;
constructor(private $window:IWindowService,
private MSSCustomerService:IMSSCustomerService) {
'ngInject';
const data = this.MSSCustomerService.availabilityData;
console.log("Customer service", data);
}
get availabilityData():IPieData {
if (angular.isUndefined(this.chartData.availability)) {
This is the data what I want to use.
MSSCustomerService.availabilityData
has interface in other page
const data = this.MSSCustomerService.availabilityData;
if (angular.isDefined(data)) {
// this.chartData.availability = {
// labels: ['up', 'down'],
// data: [data.up, data.down],
// colours: ['#058DC7', '#50B432'],
// };
this.reflow();
Here, the below using Highcharts
this.chartTest = {
options: {
chart: {
type: 'pie',
},
},
series: [{
I want use the above variable inside.
data: [data.down, data.up]//Here, should show up the data using the above variable
// data: [10, 10]
}],
title: {
text: false
},
loading: false
};
}
}
return this.chartData.availability;
}
}
export const mssPiesComponent:IComponentOptions = {
template: `
<section class="card card-block m-t-10">
<h2 class="display-8">
Stats
</h2>
<p class="pull-right">Total Circuits: [[ $ctrl.numCircuits ]]</p>
<pie-chart title="Availability" chart-data="$ctrl.availabilityData.data" labels="$ctrl.availabilityData.labels" pie-colors="$ctrl.availabilityData.colours"></pie-chart>
<div>
[[ $ctrl.availabilityData.labels ]]
[[ $ctrl.availabilityData.data ]]
</div>
<div>
<!--Pie chart using high chart-->
<highchart id="chart1" config="$ctrl.chartTest"></highchart>
</div>
</section>
`,
controller: MSSPiesController,
bindings: {
numCircuits: '#',
}
};

Resources