Adding External XML to a VisualForce DataTable/List - salesforce

I am making an external call to a Server and returning XML (HTTPResponse). I then use a DOM parser to get a list of items.
How can I add the list of items to a DataTable/DataList?
How can I parse the XML structure into a Salesforce structure within the class itself?
Thank you
Hi eyesscream. All is working fine, except one thing. I needed to get deep in XML
Dom.XMLNode rootElement = doc.getRootElement();
for (Dom.XmlNode assets : rootElement.getChildElements()) {
if (assets.getName().trim() == 'models') {
for (Dom.XmlNode asset : assets.getChildElements()) {
if (asset.getName().trim() == 'model') {
for (Dom.XmlNode serial : asset.getChildElements()) {
if (serial.getName().trim() == 'modelNumber') {
text = serial.getText().trim();
allOptons.add(new SelectOption(text, text));
}
}
}
}
}
}
on VF page it duplicates the results. Why?

Go through your XML adding elements to a list of strings of wrapper objects if you need to store more than 1 parameter. Then such list can be assigned to dataTable, pageBlockTable, repeat etc tags without any problems. It's not like these tags work only on standard sObjects.
For a simple list of Strings with checkboxes you don't even need any helper classes.
public class StackXml{
public List<SelectOption> allOptions {get;private set;} // this will hold serial numbers for use in VF page.
// if you wouldn't plan to use VF with checkboxes, simple List<String> would be enough
public List<String> selectedOptions {get;set;}
public StackXml(){
allOptions = new List<SelectOption>();
selectedOptions = new List<String>();
String xmlString = '<serials><serialNumber>ver123</serialNumber><serialNumber>ver456 </serialNumber>' +
'<intrusion>something to prove it will be skipped</intrusion>' +
'<serialNumber>abc007</serialNumber></serials>';
Dom.Document doc = new Dom.Document();
doc.load(xmlString);
Dom.XMLNode rootElement = doc.getRootElement();
for(Dom.XmlNode node : rootElement.getChildElements()){
if(node.getName().trim() == 'serialNumber') {
String text = node.getText().trim();
allOptions.add(new SelectOption(text, text));
}
}
}
public void assign(){}
}
<apex:page controller="StackXml">
<apex:form>
<apex:selectCheckboxes value="{!selectedOptions}" layout="pageDirection">
<apex:selectOptions value="{!allOptions}"/>
</apex:selectCheckboxes>
<apex:commandButton value="Assign" action="{!assign}"/>
</apex:form>
<hr/>
<p>You have selected:</p>
<apex:dataList value="{!selectedOptions}" var="o">{!o}</apex:dataList>
</apex:page>

Related

ReactiveUI "Compelling Example" how to refresh the search results

My question is in regards to the "Compelling Example" given for ReactiveUI where as a person types in a search bar, the search occurs asynchronously. Suppose though I wanted to provide my user with a way to refresh the current search results. I could just ask them to backspace in the search bar and retype their last character. However, they are asking for a "Refresh" button because it's not obvious to them how to refresh the current results.
I can't think of how to do this within the context of the example:
public class TheViewModel : ReactiveObject
{
private string query;
private readonly ObservableAsPropertyHelper<List<string>> matches;
public TheViewModel()
{
var searchEngine = this.ObservableForProperty(input => input.Query)
.Value()
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(800))
.Where(query => !string.IsNullOrWhiteSpace(query) && query.Length > 1);
var search = searchEngine.SelectMany(TheSearchService.DoSearchAsync);
var latestResults =
searchEngine.CombineLatest(search, (latestQuery, latestSearch) => latestSearch.Query != latestQuery ? null : latestSearch.Matches)
.Where(result => result != null);
matches = latestResults.ToProperty(this, result => result.Matches);
}
public string Query
{
get
{
return query;
}
set
{
this.RaiseAndSetIfChanged(ref query, value);
}
}
public List<string> Matches
{
get
{
return matches.Value;
}
}
}
Does anyone have any suggestions on how I could capture a command from a button and re-execute the existing search without clearing out their current search text?
You can merge the existing observable of Query changes with a new observable that returns the current Query when the refresh button is pressed.
First a command for the refresh button:
public ReactiveCommand<Unit, String> Refresh { get; private set; }
Then you create the command and assign it, and create a merged observable of the two observables:
Refresh = ReactiveCommand.Create<Unit, String>(() => Query);
var searchEngine = Observable.Merge(
this.ObservableForProperty(input => input.Query).Value().DistinctUntilChanged(),
Refresh)
.Throttle(TimeSpan.FromMilliseconds(800))
.Where(query => !string.IsNullOrWhiteSpace(query) && query.Length > 1);
The rest can stay unchanged.

What will be approach in Composite C1 for Creating Custom Form?

I wanted to create a page like following image in Composite-C1 with File upload functionality. But I am stucked here unable to find any thing on google. What will be the best approach to do this. How to create a simple razor functions to do this. What will be in form actions.
I would go ahead and use the free and very flexible Contrib FormBuilder which you can get from here https://bitbucket.org/burningice/compositec1contrib.formbuilder. Under 'Downloads' is the zip-files, which you would go ahead and download and install as Local Packages from within the C1 Console.
For this example you would need CompositeC1Contrib.FormBuilder.0.8.7 and CompositeC1Contrib.FormBuilder.POCO, and if you don't already use the Contrib.Core package, you need grab that one from here https://bitbucket.org/burningice/compositec1contrib/downloads. Install them in this order
Core
FormBuilder
FormBuilder.POCO
When that is all done, you need to create two thing, the form definition and a razor file to present the form
The form defintion is a .cs class file, kinda like a Model in NVC, with a number of properties and a submit handler
Form.cs
using System;
using CompositeC1Contrib.FormBuilder;
using CompositeC1Contrib.FormBuilder.Attributes;
using CompositeC1Contrib.FormBuilder.Validation;
using CompositeC1Contrib.FormBuilder.Web.UI;
namespace StackExchange
{
[FormName("Forms", "Feedback")]
public class Form : IPOCOForm
{
[FieldLabel("Feedback type")]
[RequiredField("Required")]
[DropdownInputElement]
public string FeedbackType { get; set; }
[FieldLabel("Version")]
[RequiredField("Required")]
[DropdownInputElement]
public string Version { get; set; }
[FieldLabel("Attachment")]
[RequiredField("Required")]
public FormField File { get; set; }
[FieldLabel("Version")]
[RequiredField("Required")]
[TextAreaInputElement]
public string Description { get; set; }
public void Submit()
{
throw new NotImplementedException();
}
}
}
The razor file is what controls the layout of the form. Out of the box it has helper methods to just dump all your fields downwards, you're free to add any html, markup and styling in it as you want.
Go ahead and create a .cshtml file named Feedback.cshtml and put in in your ~/App_Data/Razor/Forms folder
#inherits POCOBasedFormsPage<Feedback>
#if (IsSuccess && (SuccessResponse != null && !SuccessResponse.IsEmpty))
{
#EvaluateMarkup(SuccessResponse.Root)
}
else
{
#EvaluateMarkup(IntroText.Root)
using (BeginForm(new { #class = "form-horizontal" }))
{
#WriteErrors()
#WriteAllFields()
#WriteCaptcha()
<div class="control-group submit-buttons">
<div class="controls">
<input type="submit" name="SubmitForm" class="btn btn-primary" value="Send Enquiry" />
</div>
</div>
}
}
Now you're ready to insert the form on a page on in a template as you'd like. It will turn up as a function named Forms.Feedback and is used like any other C1 Function as you're used to.

Create UI components on page load

I am currently working on oracle adf task flows and regions and I want to create and update some UI components on page load and for this I am using method call activity as default.The problem is that I am getting null values following is my code in the bean that executes on the method call.
package view;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import oracle.adf.view.rich.component.rich.output.RichOutputText;
public class testBean {
public testBean() {
}
public String testMethod() {
// Add event code here...
FacesContext facesContext = FacesContext.getCurrentInstance();
UIViewRoot root = facesContext.getViewRoot();
RichOutputText text = ( RichOutputText )root.findComponent( "r1:ot1" );
text.setValue( "Adding text on run time" );
return "product";
}
}
The set value method returning me null may be it is because the fragment product.jsff which is the view activity is not initiated and the output text with ot1 returning null.
The better approach to achieve the setting of value is to have a property in your bean say: textValue and then bind the value attribute of your ot1 with the property of the bean.
class TestBean{
private String textValue;
public String testMethod() {
textValue = "Adding text on run time";
}
public String getTextValue(){
return textValue;
}
}
Your JSPX would be:
<af:outputText id="ot1" value=#{beanName.textValue}" />

Invalid field Email for SObject AggregateResult in VisualForce

I want to display the AggregateResult on my Visualforce page but it is generating the following error " Invalid field Email for SObject AggregateResult"
Below is my code:
public with sharing class searchDuplicate {
public AggregateResult[] con{get;set;}
public searchDuplicate()
{
find();
}
public void find(){
con = [select Email from Contact group by Email having count(Email) > 1];
System.debug(con);
}
}
Below is my visualforce page code:
<apex:page controller="searchDuplicate">
<apex:pageBlock title="Searching for Duplicate Contacts Record">
</apex:pageBlock>
<apex:pageBlock title="Contacts">
<apex:dataTable value="{!con}" var="c" border="2" cellspacing="5" cellpadding="5">
<apex:column headerValue="Email" value="{!c['Email']}" />
</apex:dataTable>
</apex:pageBlock>
</apex:page>
kindly Make a correction if possible
public with sharing class searchDuplicate {
public list <con> conList{get;set;}
public class con{
public string Email {get;set;}
public con( string email){
this.Email = email;
}
}
public searchDuplicate()
{
find();
}
public void find(){
conList = new list <con>();
for( AggregateResult ar : [select Email from Contact group by Email having count(Email) > 1];){ conList.add(new con(string.valueOf(ar.get('Email')))) }
}
}
Aggregate results (and their fields/columns) come as generic Objects, not sObjects. Therefore there's no obj.get('somefieldname') you can call on them.
Your best option might be to make a helper class that has String email; Integer count; fields and loop through the query results populating a list of objects of this helper class.
You could also use Map<String, Integer> but that'd come to VF as not sorted alphabetically.
See https://salesforce.stackexchange.com/questions/7412/count-a-grouped-by-soql if you need a code sample.
Although the other answers are correct in solving your problem, what you have is actually a bug in SalesForce.
The way to resolve this without creating a custom object is to separate the into two - The "headerValue" and "value" both being set cause this error.
You want to change it to this:
<apex:dataTable value="{!con}" var="c" border="2" cellspacing="5" cellpadding="5">
<apex:column headerValue="Email" >
<apex:outputText>{!c['Email']}</apex:outputText>
</apex:column>
</apex:dataTable>
Thanks,
Michael

apex:commandButton can't return nothing?

I have:
<apex:commandButton action="{!whatever}" value="myButton" reRender="sectionX" />
And
public String whatever(){
return 'ok';
}
It doesn't work (returns 401 Unauthorized), but if I write:
public void whatever(){
// some code
}
works fine.
The question is: how can I return something (a JSON or a Page) to this call?
Thanks
CommandButtons are used to execute some code on the server and they return a PageReference, not a string/json value.
<apex:commandButton action="{!whatever}" value="myButton" reRender="sectionX" />
So the method whatever should do the work and then assign the result to a public property on the controller so the page can display the result.
The rerender attribute says to reload the data in the outputpanel sectionX. SectionX needs to enclose the results you want to display from the commandbutton action.
public class myController {
public string Result {get;set;}
public PageReference whatever() {
// do your work here
Result = DateTime.Now();
return null;
}
}
Visualforce
<apex:outputpanel id="sectionX">{!Result}</apex:outputpanel>
Every time you click myButton command button the outputpanel will display a new datetime string.
An afterthought: If you want to put a string result/JSON into a javascript method, you can do something like the following.
<script>
function processJSON(val) {
var res = JSON.parse(val);
// do your work here
}
</script>
<apex:outputpanel id="sectionX">
<script>
processJSON("{!Result}");
</script>
</apex:outputpanel>
In your example commandbutton code you used rerender so you dont need to return a non null PageReference. If, on the other hand, you want to go to another page when you click the commandbutton, you would not set the rerender attribute and you would need to return a non-null PageReference,
ie
public PageReference whatever() {
return Page.MyVisualforcePage;
}
Not realy. Look here
As for me, I used method which returns PageReference variable.
Better to do like this:
public PageReference whatever(){
PageReference pageRef = null; // null won't refresh page at all if I'm not mistaken
// some cool logic goes here
if(toNavigate) {
pageRef = new PageReference('here is some URL to which user must be navigated');
} else if(toRefreshCurrent) {
pageRef = ApexPages.currentPage();
}
return pageRef;
}
About returning page - look here.

Resources