How to add attributes all the to XMLElements in Spyne Array - arrays

I am using spyne Array to transform a JSON list and I need to add the "id" attribute to the "referral" parent node in the final XML.
This is the final XML I am expecting:
<viewOutboundResponse user="rayners">
<referral id="123">
<status>SUBMITTED</status>
<from>
<outlet id="12345">ABC</outlet>
</from>
<to>
<outlet id="6789">XYZ</outlet>
</to>
<date>2015-01-14</date>
<client>Bloggs</client>
<daysToExpiry>3</daysToExpiry>
</referral>
<referral id="456">
<status>REJECTED</status>
<from>
<outlet id="101112">DEF</outlet>
</from>
<to>
<outlet id="131415">S2X Demo</outlet>
</to>
<date>2004-01-15</date>
<client>Gobbs</client>
<daysToExpiry>7</daysToExpiry>
</referral>
</viewOutboundResponse>
Here is my code:
class ReferralSummaryType(ComplexModel):
__type_name__ = 'referral'
type_info = {'id': XmlAttribute(Integer),
'status': Unicode,
'from': ReferralFromType,
'to': ReferralToType,
'date': Date,
'client': Unicode,
'daysToExpiry': Integer}
class OutboundResponseType(ComplexModel):
__mixin__ = True
referral = Array(ReferralSummaryType)
But the output I am getting is:
<viewOutboundResponse user="rayners">
<referral>
<referral id="123">
<status>SUBMITTED</status>
<from>
<outlet id="12345">ABC</outlet>
</from>
<to>
<outlet id="6789">XYZ</outlet>
</to>
<date>2015-01-14</date>
<client>Bloggs</client>
<daysToExpiry>3</daysToExpiry>
</referral>
<referral id="456">
<status>REJECTED</status>
<from>
<outlet id="101112">DEF</outlet>
</from>
<to>
<outlet id="131415">S2X Demo</outlet>
</to>
<date>2004-01-15</date>
<client>Gobbs</client>
<daysToExpiry>7</daysToExpiry>
</referral>
</referral>
</viewOutboundResponse>

So your question says
I need to add the "id" attribute to the "referral" parent node in the
final XML.
Your desired output has a sequence of referral nodes without a wrapping referral node and the result you are seeing is a sequence of embedded referral nodes (each with the id attribute) but no ID on the wrapping node.
So there is a bit of a conflict there. If it is your need to have an ID in the wrapping referral node, then I think you might need to change your response and add a class for the wrapper type:
class ReferralWrapperType(ComplexModel):
__type_name__ = 'referral'
id = XMLAttribute(Integer)
referral = Array(ReferralSummaryType)
class OutboundResponseType(ComplexModel):
__mixin__ = True
referral = ReferralWrapperType
whereas if what you need is what is shown in what you say is the final XML that you are expecting then from the Spyne array documentation I am led to believe that you could perhaps try:
class OutboundResponseType(ComplexModel):
__mixin__ = True
referral = ReferralSummaryType.customize(max_occurs="unbounded")
Caveat - I'm very very very new to Spyne.
Edited to use max_occurs="unbounded" instead of max_occurs=float('inf') per this spyne bug.

According to the Spyne documentation (http://spyne.io/docs/2.10/manual/03_types.html#arrays), using
referral = ReferralSummaryType.customize(max_occurs="unbounded")
Resolved my issue.
Thanks!

Related

Lightning-record-view form is not displaying the record with the id that is fetch from an apex class. Salesforce LWC,Apex

I have a record view for which the id is from apex class and then wired it and assigned to a variable, but the record is not displaying. below is my code.
apex class to get the record id of the record owned by the user
#AuraEnabled(cacheable=true)
public static Wallet__c getWalletInfo(){
String userId = UserInfo.getUserId();
return [SELECT Id From Wallet__c WHERE OwnerId =: userID LIMIT 1];
}
.js class - assigned the data to getId
import getWalletInfo from '#salesforce/apex/CustomWalletHandler.getWalletInfo';
import wallet from '#salesforce/schema/Wallet__c';
import walletName from '#salesforce/schema/Wallet__c.Name';
import walletBalance from '#salesforce/schema/Wallet__c.balance__c';
import walletFrom from '#salesforce/schema/Wallet__c.added_from__c';
export default class CustomWallet extends LightningElement {
objectName = wallet;
name = walletName;
balance = walletBalance;
from = walletFrom;
getId;
isUser = true;
#wire (getWalletInfo,{})
walletData({error, data}){ //data is record Id
if(data){
this.getId = data;
console.log(this.getId);
this.isUser = false;
}else if(error) {
// error handling
console.error(error.body.message);
}
}
}
html - if user has no recordc Create Wallet will display and if user has record only the record will display.
<template>
<lightning-card>
<lightning-tabset>
<template if:true={isUser}>
<lightning-tab label="Create a Wallet">
<lightning-record-form
object-api-name="Wallet__c"
columns="2"
layout-type="Full"
></lightning-record-form>
</lightning-tab>
</template>
<template if:false={isUser}>
<lightning-tab label="My Wallet">
<lightning-record-view-form
record-id={getId}
object-api-name={objectName}>
<div class="slds-box">
<lightning-output-field field-name={name}>
</lightning-output-field>
<lightning-output-field field-name={balance}>
</lightning-output-field>
<lightning-output-field field-name={from}>
</lightning-output-field>
</div>
</lightning-record-view-form>
</lightning-tab>
</template>
</lightning-tabset>
</lightning-card>
I think you overcomplicated it a bit. What do you get when you put simpler references to object & fields?
<lightning-record-view-form
record-id={getId}
object-api-name="Wallet__c">
<div class="slds-box">
<lightning-output-field field-name="Name"></lightning-output-field>
<lightning-output-field field-name="Balance__c"></lightning-output-field>
<lightning-output-field field-name="Added_From__c"></lightning-output-field>
</div>
</lightning-record-view-form>
And your apex method is returning whole Wallet__c object, not just the Id. With just 1 field populated but still. You can tell by seeing curly braces in your console.log's output. So you need either this.getId = data.Id; in JS or record-id={getId.Id} in HTML. Or make Apex return just an Id variable (and null if no results found I guess?)

React Router dynamic routing based on JS Array

I'm making a simple marketplace, that has a home page with product cards - the cards are generated from an internal JS file (Data.js). It goes like this because I need to generate random names, and I use a function for that. The array goes like this:
let Data= [{
id: i,
nomeCompleto: nomeCompleto,
valor: preco(),
isFavorite: false,]}
When I click on the card, I use a dynamic route:
<Route path ='produto/:id' element={productSpecs}/>
It is working fine, the xxx/produto/id always matches the product id. The problem is, it's returning all of the array from Data. I need it to return only Data[(id - 2]).
As it is now, productSpecs is defined on the App.js as below, replacing props on ProductInfo:
const productSpecs = Data.map(item => {
return (
<ProductInfo
key = {item.id}
id = {item.id}
img = {item.img}
nomeCompleto = {item.nomeCompleto}
valor = {item.valor}
favorite = {item.isFavorite}
/>
)
})
Should I define the props on the Product Info JSX? If so, how?
Following your question, you could retrieve the id param inside of the ProductInfo and do a find() on the Data to get the product you're trying to display.
function ProductInfo() {
const { id } = useParams()
const product = Data.find(product => product.id === id);
...
}
and on the Routing level you could have
<Route path ='product/:id' element={<ProductInfo />}/>

How to post an array of emails as cfhttpparam?

so I am trying to post to an API using Coldfusion with an array of emails.
For a quick over view of the API schema,
{
"emails":["foo#bar.com", "bar#foo.com"],
"orgId":1,
"subject":"foobar",
"body":"foobar",
"sender":"foobar#com"
}
Now this is my coldfusion script
<cffunction name="inviteusers" access="public" returntype="any">
<cfset var data = "" />
<cfhttp url="urlserver#UserInvite" method="post" username="#username#" password="#urlpass#" result="data">
<cfhttpparam name="emails" this is array or emails>
<cfhttpparam name="orgID" type="formType" value="1">
<cfhttpparam name="body" type="formType" value="this is the body">
<cfhttpparam name="sender" type="formType" value="hmm#yahoo.com">
</cfhttp>
</cffunction>
The emails is where I am stuck at.. I'm not sure how to approach this problem..
Thank you guys!
Allrighty,
here is how I answered this question. Since I am working on an MVC framework, in the view where I have the form, I've created a JQuery post function to the function in a controller.
I have an html input where a user can type in any number of emails separated by comma. I have a javascript function that takes the value of the input and splits them at 'comma' then add them to an array object.
Since the API is structured as this :
{
"emails":["foo#bar.com", "bar#foo.com"],
"orgId":1,
"subject":"foobar",
"body":"foobar",
"sender":"foobar#com"
}
in my $.post() function I have an object for to be used as the data:
var myData = {
"emails" : myEmails, //This myEmails is an array['fooBar#.com', 'barfoo#.com'] of emails from the single email input.
"orgId" : 1,
"subject" : $('#vgridSubject').val(),
"body" : $('#vgridText').val(),
"sender" : "foobar#ls.com"
}
now in my controller, here is how I handle the array of emails
<cfscript>
sendInvites = postUserInvite(emails = FORM['EMAILS[]'], orgID = FORM.orgID, subject = FORM.subject, body = FORM.body, sender = FORM.sender)
</cfscript>
Take note of FORM['EMAILS[]'] as this lets me access the values from form scope.
Link to the form array Working with Form Arrays in ColdFusion?

How to pass a current loop value to class method in Tapestry?

I want to dynamically show available menus of links to pages depending on which type of user is logged in using Tapestry.
Part of my code in Layout.tml looks like this:
<div class="header">
<t:if t:test="userLoggedIn">
<div class="menu">
<ul>
<t:loop t:type="loop" source="pageNames" value="pageName" class="prop:classForPageName">
<t:if t:test="isUserAllowedOnPage('pageName')">
<li>
<t:pagelink page="prop:pageName.name">${pageName.displayName}</t:pagelink>
</li>
</t:if>
</t:loop>
</ul>
</div>
</t:if>
<div style="clear:both;"></div>
</div>
In my Layout.java I have a following method:
public boolean isUserAllowedOnPage(String pageName) {
// My logic here, returns either true or false
}
The problem is, I do not know how to pass the actual page name parameter to isUserAllowedOnPage(String pageName) method, because with the following line of tml code
"isUserAllowedOnPage('pageName')"
I pass an actual string, "pageName" instead of one of the desired values (for example, "Index", "About", "Contacts"...).
Your loop specifies value="pageName" which means that tapestry will update the pageName property in your page each time it iterates through the loop. So, you don't need to pass it to a method since it's already set each time you invoke the method.
You could just do the following:
TML
<t:loop source="pageNames" value="pageName">
<t:if t:test="userAllowedOnPage">
...
</t:if>
</t:loop>
Java
#Property
private List<String> pageNames;
#Property
private String pageName;
...
public boolean isUserAllowedOnPage() {
// some calculation based on pageName
}
You can pass value to method without quotes as if you write this expression in java code:
<t:if t:test="isUserAllowedOnPage(pageName)">
</t:if>
Or:
<t:if t:test="isUserAllowedOnPage(getPageName())">
</t:if>

Unable to bind Component attribute with controller

I am trying to develop a visualforce custom component which takes an attribute from a visual force page. I need to access that attribute in controller's Constructor so that i can brings some records from database and i need to display those records in the Component. But problem is that i am not getting Attribute value in Controller.
See the below code to understand the problem clearly..
Controller :
public with sharing class AdditionalQuestionController {
public String CRFType {get;set;}
public AdditionalQuestionController () {
system.debug('CRFType : '+CRFType);
List<AdditoinalQuestion__c> lstAddQues = [Select AddQues__c from AdditoinalQuestion__c wehre CRFType = :CRFType];
system.debug('lstAddQue : '+lstAddQue);
}
}
Component :
<apex:component controller="AdditionalQuestionController" allowDML="true">
<apex:attribute name="CRFType" description="This is CRF Type." type="String" required="true" assignTo="{!CRFType}" />
<apex:repeat value="{!lstAddQue}" var="que">
{!que}<br />
</apex:repeat>
</apex:component>
VisualForce page :
<apex:page >
<c:AdditionalQuestionComponent CRFType="STE" />
</apex:page>
Thanks,
Vivek
I believe the issue here is that you're expecting the member variable to have a value inside the constructor — the snag is that the instance of the class is being constructed! It doesn't exist yet and so there is no way that a non-static member variable could be given a value prior.
Instead of doing the query in your constructor, specify your own getter for lstAddQue and do the query in there when you need the data. Of course, you may want to cache the value so that the query is not run every time, but from the looks of things that won't be relevant here.
Setter methods on the attributes in a VF component appear to be called after the constructor has returned, unfortunately. Here's an alternative solution for your controller that uses a getter method to populate your list (which would be called after your CRFType member variable has been set):
public with sharing class AdditionalQuestionController {
public String CRFType {set;}
public AdditionalQuestionController () {
system.debug('CRFType : '+CRFType); // this will be null in the constructor
}
public List<AdditoinalQuestion__c> getLstAddQue() {
system.debug('CRFType : '+CRFType); // this will now be set
List<AdditoinalQuestion__c> lstAddQues = [Select AddQues__c from AdditoinalQuestion__c wehre CRFType = :CRFType];
system.debug('lstAddQue : '+lstAddQue);
return lstAddQue;
}
}

Resources