Iframe issue: Salesforce not fetching parent in SOQL nested query - salesforce

SITUATION: Hi I have a query THAT functions well & as per expectations in salesforce vf page only.
PROBLEM It returns the output without its parent object when calling from an iframe.
The code in apex:
public class showServiceHistory {
CKSW_BASE__Service__c services;
String id = ApexPages.currentPage().getParameters().get('id');
String x;
public myValues()
{
services = [SELECT id, name, (SELECT Name, Previous_Status__c, New_Status__c, Reason_Code__c, comment__c FROM Service_Status_History__r) FROM CKSW_BASE__Service__c WHERE id=:id];
}
public String getxx()
{
x=JSON.Serialize(services);
return x;
}
}
The Code In VF
< apex:page controller="myValues" >
< apex:pageBlock title="{!xx}" >
< /apex:pageBlock >
< /apex:page >
Output From Salesforce
{"attributes":{"type":"CKSW_BASE__Service__c","url":"/services/data/v38.0/sobjects/CKSW_BASE__Service__c/sss"},"Id":"s","Name":"S","Service_Status_History__r":{"totalSize":6,"done":true,"records":[{"attributes":{"type":"Service_Status_History__c","url":"/services/data/v38.0/sobjects/Service_Status_History__c/ss"},"Service__c":"asss","Id":"uu","Name":"yyy","Previous_Status__c":"xyz","New_Status__c":"y","Reason_Code__c":"xyz","Comment__c":"abc"}]}
And
Output from iframe
{"attributes":{"type":"CKSW_BASE__Service__c","url":"/services/data/v38.0/sobjects/CKSW_BASE__Service__c/444"},"Id":"444","Name":"xyz"}
From the Vf page I get the desired output with full value, but from an iframe in my force.com url the parent object (nested query) is not available.
However, when I call only parent with a simple dedicated query, it returns the value in both(iframe and url) places.
WHY MY NESTED SOQL IS UNABLE TO GET THE PARENT OBJECT. WHAT I AM MISSING HERE??
Thanks in advance.
Please help.
Output from Iframe

Have you checked your FLS?
Build -> Develop -> Sites -> -> Public Access Settings
This is the culprit most of the times on Force.com outcome.

Yes I already checked, It granted public access. And even I am able to
see them when converting and printing in JSON format. But I can't see
them in iframe if printed with parse object form.
Hence it worked for me by sending values in Json string format and by
parsing it over there.
In Vf page
<apex:page Controller="showServiceHistory" sidebar="false" showheader="false">
<html>
<head>
<!--<meta http-equiv="refresh" content="20" ></meta> -->
</head>
<a id="history_data" style="display:none;">{!history}</a>
<a id="service_data" style="display:none">{!service}</a>
<style>
table {
width: 100%;
}
table,
th,
td {
border-collapse: collapse;
color: #3088D0;
}
th,
td {
padding: 5px;
text-align: left;
color: #1F497D;
}
tr {
//color: #337AB7;
}
table#t01 tr:nth-child(even) {
background-color: #DCE6F1;
//color: #337AB7;
}
table#t01 tr:nth-child(odd) {
background-color: #fff;
}
table#t01 th {
background-color: #B8CCE4;
//color: #000015;
}
a:link {
color: #62B3E2;
}
a:visited {
color: #62B3E2;
}
</style>
<table id="t01">
<thead>
<tr>
<th>
Name
</th>
<th>
Previous Status
</th>
<th>
New Status
</th>
<th>
Comment
</th>
</tr>
</thead>
<tbody id="show_values">
</tbody>
</table>
<script>
function x()
{
var history={}; var service={};
history=JSON.parse(document.getElementById("history_data").innerHTML);
service=JSON.parse(document.getElementById("service_data").innerHTML);
var show='';
for(var i=0;i<history.length;i++)
{
show=show+'<tr><td>'+history[i].Name+'</td><td>'+history[i].Previous_Status__c+'</td><td>'+history[i].New_Status__c+'</td><td>'+history[i].Comment__c+'</td><td>'+service.CKSW_BASE__Location__c+'</td></tr>';
}
document.getElementById("show_values").innerHTML=document.getElementById("show_values").innerHTML+show;
}
x();
</script>
</html>
In apex code page
public class showServiceHistory {
List<Service_Status_History__c> histories;
String x;
CKSW_BASE__Service__c services;
String id = ApexPages.currentPage().getParameters().get('id');
public showServiceHistory()
{
services = [SELECT CKSW_BASE__Resource__c, CKSW_BASE__Location__c, (SELECT Name, Previous_Status__c, New_Status__c, comment__c FROM Service_Status_History__r) FROM CKSW_BASE__Service__c WHERE id=:id];
histories = services.Service_Status_History__r;
}
public String getService()
{
return JSON.Serialize(services);
}
public String getHistory()
{
return JSON.Serialize(histories);
}
}

Related

Display Child field at vfp from Controller

I'm trying to display subqueries columns on my Visualforce page but I can't.
Apex controller:
public class FormController {
private final FormularioDeVisita__c formulario;
public FormularioVisitaPdfController() {
if(ApexPages.currentPage().getParameters().get('id') != null){
formulario = [
SELECT
ChequeEmpresa__c, SedePropria__c, CNPJ__c, MercadoExternoCliente__c, DataFundacao__c,
(SELECT
FormInfoPercent__c, FormInfoText__c, FormInfoCheckbox__c, FormInfoDate__c, FormInfoCurrency__c,
FormInfoPercentDecimal__c, FormularioVisita__c
from FormularioVisitaChild__r)
from FormularioDeVisita__c
WHERE Id = :ApexPages.currentPage().getParameters().get('id')];
}
}
public FormularioDeVisita__c getformularioVisita() {
return formulario;
}
public PageReference save() {
update formulario;
return null;
}
}
Example from Visualforce page:
<tr>
<td class="table td">Mercado livre?</td>
<td class="table td_right">{!formularioVisita.MercadoLivre__c}</td>
</tr>
Using like that I can display the columns from the father without problems, but when I try to display from children, I can't.
I didn't find any information about it.
Display children columns in my HTML in Visualforce.
You need <apex:repeat>, <apex:datatable>, <apex:pageBlockTable> tags.
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_repeat.htm contains example of using repeat to access Account.Cases. In your code it'll be repeat over {!formularioVisita.FormularioVisitaChild__r}

Angular materials Mat-table, not working with in the html with .push

I am working on an infinite scroll in angular 8. I am using an angular materials table to display my data.
Html:
<mat-table [dataSource]="displayOfMassSendObjects"
infinite-scroll
[infiniteScrollDistance]="scrollDistance"
[infiniteScrollUpDistance]="scrollUpDistance"
(scroll)="onScrollDown()"
(scrollup) = "onScrollUp()"
>
<ng-container id = "companyNameColumn" matColumnDef="companyName">
<mat-header-cell id = "companyNameTitle"
*matHeaderCellDef>CompanyName</mat-header-cell>
<mat-cell class = "companyNameData" *matCellDef="let row">
{{row.companyName}}</mat-cell>
</ng-container>
<ng-container id = "emailColumn" matColumnDef="email">
<mat-header-cell id = "emailTitle"
*matHeaderCellDef>Email</mat-header-cell>
<mat-cell class = "emailData" class="email" *matCellDef="let row">
{{row.email}}</a></mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="tableColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: tableColumns"> </mat-row>
</mat-table>
On load I have 10 records showing up in the table. When I scroll down, I am expecting that more records will populate in the HTML but they are not. The records are however being added to the array in the console.log(). I think the problem is that the HTML Angular Materials is not recognizing the .push because when I substitute .push for .slice, the records show up in the HTML, however don't want the app to work like that.
Here is my component for the table where I want the scroll bar:
export class MassSendComponent implements OnInit {
sum = 10;
globalList = [];
displayOfMassSendObjects: MassSend[];
tableColumns : string[] = ['ispNumber','companyName', 'email', 'taxId']
constructor(
private mockMassSendService: MockMassSendService,
) {}
ngOnInit(): void {
this.getMassSendData();
}
getMassSendData() {
this.mockMassSendService.getMassSendData()
.subscribe(massSendObjects => {
this.globalList = massSendObjects;
this.displayOfMassSendObjects = massSendObjects.slice(0,
this.sum);
});
}
getMoreData() {
this.displayOfMassSendObjects.push(this.globalList[this.sum]);
}
onScrollDown(): void {
console.log(this.displayOfMassSendObjects);
this.getMoreData();
this.sum += 1;
}
}
I also have a service method being called:
export class MockMassSendService {
constructor() { }
getMassSendData(): Observable<MassSend[]> {
return of(mockMassSend);
}
}
You can use displayOfMassSendObjects = new MatTableDataSource(this.displayOfMassSendObjects); every time you fetcb new data, this will initialize a new datasource object.
The reason you are not able to see newly added rows is that
Mat table only reflects changes when the reference to datasource is changed that's why when you use slice method it works fine.

Creation of a Formula Blot (Hierarchical Tags)

Creation of a complex formula blot, such as the one below, is successful using an Embed, but it works only in a single instance. All other instances are truncated. Attempts to create it as an Inline or Block resulted in errors.
I am developing a graphic formula editor, with a dialog and toolbars of its own, and it is successfully getting the delta from an existing blot. Unfortunately, saving more than one formula fails, and replacing an existing formula fails. When saving more than one formula, only the top level spans are saved for all but the first.
It isn't clear from the documentation if the tag hierarchy can be used as an Inline or Block element.
As a side note, I am building a complete Quill npm module for Angular 7+ apps that includes a number of other quill modules as well, translated to Typescript. The npm module will support WCAG compliance with large buttons, etc. that can be toggled.
Example tag hierarchy to be used as a blot:
<span class="pl3-quill-formula-blot" data-id="pl3qfml_1560288135645" data-editors="[{"id":1560288133767,"parentId":null,"depth":0,"position":0,"fElement":{"name":"cube root","text":"∛","type":"O","shape":"R","latex":null,"values":["x"],"nValues":1}},{"id":1560288133768,"parentId":0,"depth":0,"position":1,"fElement":{"name":"-EMPTY-","text":"","type":"S","shape":"C","latex":null,"latexCb":null,"values":[""],"nValues":1}}]">
<span contenteditable="false">
<span class="katex">
<span class="katex-mathml"><math><semantics><mrow><mroot><mi>x</mi><mn>3</mn></mroot></mrow><annotation encoding="application/x-tex">\sqrt[3] {x} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height: 1.04em; vertical-align: -0.23972em;"></span><span class="mord sqrt"><span class="root"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.658556em;"><span class="" style="top: -2.83634em;"><span class="pstrut" style="height: 2.5em;"></span><span class="sizing reset-size6 size1 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.80028em;"><span class="svg-align" style="top: -3em;"><span class="pstrut" style="height: 3em;"></span><span class="mord" style="padding-left: 0.833em;"><span class="mord mathdefault">x</span></span></span><span class="" style="top: -2.76028em;"><span class="pstrut" style="height: 3em;"></span><span class="hide-tail" style="min-width: 0.853em; height: 1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,
-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,
-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,
35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,
-221c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467
s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422
s-65,47,-65,47z M834 80H400000v40H845z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height: 0.23972em;"><span class=""></span></span></span></span></span></span></span>
</span>
</span>
</span>
Blot Code:
import {Pl3QuillFormulaResult} from './pl3-quill-formula.component';
const Quill = require('quill');
const Embed = Quill.import('blots/embed');
class Pl3QuillFormulaBlotComponent extends Embed {
static blotName = 'pl3-quill-formula';
static className = 'pl3-quill-formula-blot';
static tagName = 'span';
constructor(domNode: Element, value: any) {
super(domNode);
}
static create(result: Pl3QuillFormulaResult) {
const node = super.create(result.id);
node.setAttribute('data-id', result.id);
node.setAttribute('data-editors', result.editorsAsString);
node.appendChild(result.domElement);
return node;
}
/**
* Quill uses this to return a Delta with the attributes in the return.
*/
static formats(domNode: Element) {
return {
editors: domNode.getAttribute('data-editors'),
id: domNode.getAttribute('data-id')
};
}
static value(domNode: HTMLElement) {
return {
id: domNode.dataset.id,
editors: domNode.dataset.editors
};
}
public remove() {
if (this.prev == null && this.next == null) {
this.parent.remove();
}
else {
super.remove();
}
}
}
Quill.register('formats/pl3-quill-formula', Pl3QuillFormulaBlotComponent);
This is the call to insert the formula that is not working for subsequent instances, although it works for the first formula:
if (result) {
const range = this.quill.getSelection(true);
this.quill.insertEmbed(range.start, 'pl3-quill-formula', result, Quill.sources.API);
this.quill.setSelection(range.length + 1);
}
Formula Editor UI Snapshot
The expected results are to be able to insert the formula within the editor, inline, and to be able to replace it when the formula is updated.

Iterate with ngFor on objects obtained from Firebase

I have a list of objects stored in firebase database:
I am getting this list using angular http get request. After getting it I want to iterate on a li in html template using ngFor="let subject of subjects" which gives Error:
ERROR Error: Cannot find a differ supporting object '[object Object]'
of type 'object'. NgFor only supports binding to Iterables such as
Arrays.
As I searched online, I came to know that ngFor can only be used on arrays while I am getting nested objects. Can anyone please suggest me what should I do iterate these objects.
So far I have tried Array.of which converts whole list into someArray[0]. I also tried to manually change the unique ids of objects into array indexes [0, 1, 2] which worked but when I add new subject using http post firebase automatically assigns unique id to new subject making it uniteratable.
In simple words tell me to convert nested objects into an arrayList or how can I change the firebase default behavior of assigning unique id in angular (I found something like firebase push function which I couldn't understand).
Update:
(Code from ExaminerService)
getBatchSubjects(batch){
return this.http.get(firebaseLinkGoesHere);
}
(Code from Component)
onBatchSelected(event){
this.selectedBatch = event.target.value; //getting value of a html select
this.examinerService.getBatchSubjects(this.selectedBatch)
.subscribe(
(response : Response) => {
this.selectedBatchData = response.json();
}
),(error) => {
console.log(error);
}
}
(Code from HTML Template)
<div class="batchDetails">
<table class="table table-striped">
<thead>
<tr>
<th class="text-center">S.No</th>
<th>Subject Name</th>
<th>Facilitator</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let subject of selectedBatchData.subjects; let i = index">
<td class="text-center"> {{i + 1}} </td>
<td> {{subject.name}} </td>
<td> {{subject.facilitator}} </td>
</tr>
</tbody>
</table>
</div>
You can use Object.values to turn the properties into an array. This can be done in several ways.
Method 1 - By applying the map operator to the observable data (see this stackblitz):
import { Observable } from "rxjs/Rx";
public subjects: Array<any>;
this.examinerService.getBatchSubjects(this.selectedBatch)
.map(x => (Object as any).values(x.json().subjects))
.subscribe(
(values) => { this.subjects = values; },
(error) => { console.log(error); }
);
Method 2 - With a property getter or a method of the component class (see this stackblitz):
get subjects(): Array<any> {
return (Object as any).values(this.selectedBatchData.subjects);
}
Method 3 - By converting the values in the subscribe callback (see this stackblitz):
public subjects: Array<any>;
...
this.selectedBatchData = response.json();
this.subjects = (Object as any).values(this.selectedBatchData.subjects);
Template
In the template, the ngFor directive would iterate over the subjects array:
<tr *ngFor="let subject of subjects; let i = index">
<td class="text-center"> {{i + 1}} </td>
<td> {{subject.name}} </td>
<td> {{subject.facilitator}} </td>
</tr>
try following code snippet.
ngFor="let subject of subjects|async
Update
In your ExaminerService you should import FirebaseListObservable in order to define return type FirebaseListObservable<any[]>
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
export class ExaminerService{
constructor(private db: AngularFireDatabase) {}
getBatchSubjects(batch){
return this.db.list('/subjects');
}
}
In your Component should look like this
export class ExaminerComponent implements OnInit {
movies: any[];
constructor(private examinerDb: ExaminerService) { }
ngOnInit() {
this.examinerDb.get().subscribe((snaps) => {
this.selectedBatchData = snaps;
});
}
}
Angular has pipe "keyvalue" which will let you parse your object into pairs like subject.key and subject.value

angularjs select ng-click event does not expand the control

I am trying to dynamically load the optionset of select tag on ng-click event. clicking on expand arrow fires ng-click event. Since I fetch the data at that point and bind to the select control, angularjs omits the expand event somehow, select does not expand. User has to click on the arrow one more time to see the results of the dynamically loaded options.
How can I ensure to expand the select correctly in one click while loading the options?
I tried to find a way to dynamically expand the select when the load is complete, but afaik there is no cross browser way of achieving that.
Here is the code, onclick retrieve method is being called to fetch and bind the data to the select. But click does not expand the control...
<div style="position: relative;">
<input type="text" class="inputTextFieldCell"
style="width: 215px; position: relative; top: 0; left: 0; z-index: 2; padding: 0; margin: 0;"
ng-model="subscriptionResource.Value" />
<select class="optionsCellInput selectTextFieldCell"
style="width:240px;position: absolute; top: 0; left: 0; padding: 0; margin: 0;"
ng-click="resources.retrieve(subscriptionResource, $event)"
ng-model="item" ng-options="resource as resource.Serial for resource in subscriptionResource.resourceList"
ng-change="selectChange(subscriptionResource, item)" >
</select>
</div>
Javascript:
$scope.resources = {
retrieve: function (resource, event) {
if (resource.resourceList == null) {
var reqDataRetrieveResources = { "request": null };
reqDataRetrieveResources = window.createRequest(window.definitions.messages.RetrieveResourceRequest, reqDataRetrieveResources);
reqDataRetrieveResources.request["ResourceType"] = 1;
reqDataRetrieveResources.request["SearchCount"] = 5;
$http.post(window.definitions.url, reqDataRetrieveResources).success(function (result) {
if ((result.d !== null) && (result.d.Resources !== null)) {
resource.resourceList = result.d.Resources;
return true;
}
});
return true;
}
}
}
Try to use ng-mousedown instead of ng-click. If it don't works, try to call $scope.$apply after bind your data.

Resources