London’s Calling ’17 and Visual Flow

Last 10th of February, I attended London’s Calling ’17 and I can say it was a great and funny day.

Captura de pantalla 2017-03-12 a las 19.22.17

And obviously, we had lot of opportunities to learn more about Salesforce. Actually I had the chance to run a session about Visual Flow where I got nice questions that I promised to review and answer, and here is the time for it:

1. Did you find any issue related to Communities?

When I created a new Community in my org and tried to add elements, I was not able to find the Flow Lightning Component that allows me to include visualflows in Lightning Experience. However, I can add visualforce pages, so if you have your flow embebed in a visualforce page and you set this page up to be used in Communities, then, it seems you can see your flow in the Community.

2. Did you find any issue during deployment?

Although my daily job tasks do not include deploying flows, I could say that those times that I tried I did not get any special issue to highlight. We just need to keep in mind few things, like also include those objects that flow references but this is like some other components. In addition, although in your org you have several versions, in change set you can only include the latest active one. And as I said in the session, in order to include a flow in package, it should be active, otherwise, it will not appear as an element to be included. You can find more information here.

3. What is coming in Spring ’17 release?

I talked about some Spring’17 features, but I also promised to review, the new FLS feature. But let start checking the behaviour if I do not have access to the object itself.

So having a user which profile only allows to Read and View All reservations:

Captura de pantalla 2017-03-12 a las 11.11.03.png

if I try to run the BookingSystem application, by the time I try to save the Reservation, I get an unhandled error (that’s why Salesforce encourage to cover these in the same way we do in apex) And the administrator receives an email with the log and the error:

Captura de pantalla 2017-03-12 a las 11.14.24Captura de pantalla 2017-03-12 a las 11.15.04

Let’s double check new FLS for Flow in Spring’17

Captura de pantalla 2017-03-12 a las 12.06.57

In this scenario, I have Filter Inaccessible Fields from Flow Request enabled in Process Automation Settings, and also, I have defined a Field Level Security of No Visible for Facility Price in my custom profile

Captura de pantalla 2017-03-12 a las 11.28.42.png

So, having this configuration, I have created also this flow in order to insert a new Facility via a Fast Create screen

Captura de pantalla 2017-03-12 a las 19.01.51.png

So in order to do that, I create a SObject and I use the input fields from the first screen in order to make an assignment to the SObject fields and finally pass the SObject to the Fast Create

Now, if I run the flow with the profile that doesn’t have price visibility, I can create a new record, but having an empty price.

Captura de pantalla 2017-03-12 a las 19.11.19.png

However, if I disable Filter Inaccessible Fields from Flow Request enabled in Process Automation Settings, and run the flow again, the result is different. The record is not half created and the administrator receives and email with the error.

So now, what should I do? Up to you really. You can handle the exception and provide a nice error message and don’t allow the end user to create a Facility record without the prices. However, if the field is not required for the business, you can leave this half creation.

Any other question about Visual Flow? Leave it as a comment and I will try to check it and reply you.

 

 

dreamOlé ’17 – De la Comunidad para la Comunidad

Hace un año Carolina habló conmigo para organizar algo como London’s Calling pero en España. Al principio me pareció una idea un poco descabellada. Salesforce no tiene tanto tirón ahora mismo en nuestro país, pero precisamente por eso poco a poco se convirtió en una gran idea. Y aquí estamos Inés, Laura, Carlos, Julio, Yasmina, Roger, Alba, Carolina y yo quedando 2 veces por semana a las 8am para hablar de nuestro proyecto: dreamOlé.

Os puedo asegurar que nos costó mucho trabajo decidir los puntos principales:

El nombre – ¿Por qué dreamOlé?

Buscábamos algo que tuviera tirón, alguna canción como en Londres, pero “Aquí no playa vaya vaya” no nos parecía lo ideal. Así que pensamos en una combinación de algo típico español, feria, fiesta, sol, tapas, paella … pero sin ser topicazo. Y añadir la palabra dream cómo otros eventos similares. Y tras varias votaciones … nos quedamos con dreamOlé.

El lugar – OpenTalk – Madrid

Para nuestro primer evento, decidimos ir a lo seguro, Madrid ó Barcelona ya que hay una gran red de empresas relacionadas con Salesforce y podríamos tener público. Y finalmente nos decantamos por la capital de España. Y a partir de ahí a buscar el local. De verdad, no sabía que era tan complicado que incluso te cojan el teléfono … pero finalmente encontramos el lugar ideal para nuestro primer evento. Gracias OpenTalk !!

La fecha – 1 de Junio de 2017

Los primeros 6 meses del año son complicados. Hay muchos eventos de Salesforce por Europa, incluyendo el Essentials de Madrid y Barcelona. Así que buscamos un mes bonito en Madrid y rezamos para que no coincidiera con otras charlas, ya que algunos se anuncian con poca antelación.

¡Necesitamos un Logo!

Y echamos mano de nuestro compañero Jorge para este diseño. Fue verlo y enamorarme.

dreamOle-light@2x

 

La Agenda

No iba a ser un evento distinto a otros ya celebrados. Queremos acercar Salesforce a la comunidad, por eso nos centraremos en proporcionar sesiones donde compartir conocimientos. Estamos trabando para ofrecer charlas en inglés y español y sobre temas actuales, y por supuesto dirigidos a distintos públicos: Desarrolladores, Administradores, Usuarios finales …

Por otro lado, somos una organización sin ánimo de lucro organizando un evento que cuesta dinero, por lo que necesitamos la ayuda de patrocinadores para llevarlo a cabo. Para ello los sponsors Platinum y Gold tendrán un stand durante todo el día para promocionarse. Y además organizaremos un DemoJam dónde los sponsor Platinum tendrán 3 minutos para mostrar su producto ante todos los asistentes ya que no coincidirá con ninguna charla. Y al final habrá un ganador!!

Y por supuesto, tendremos un KeyNote inicial y final. Seguimos dando la lata a toda persona conocida en este mundillo para que venga y por ahora hemos convencido a Erica Kuhl, así que yo no me la perdería.

Y a partir de ahí seguimos trabajando para que todo esté listo a tiempo

¿Quieres saber más?  Síguenos en twitter ó Visita nuestra web. Y no te olvides. ¿Quieres ser sponsor? No te lo pienses porque tenemos plazas limitadas. Encuentra toda la información aquí.

¿Te gustaría dar una charla y compartir tus conocimientos? Mándanos tus ideas a través del Speaker Submission form y recuerda que la fecha límite es el 21 de Abril.

¿Tienes dudas? Visita nuestra sección FAQ y si algo no queda claro, ponte en contacto con nosotros a través de twitter ó el correo comunidadsalesforce@gmail.com

Nos vemos!!

Logo-O (1)

De Dev 401 a App Builder Salesforce Certificación

This blog is written in Spanish but if you are looking for a place with information about App Builder Transition exam, go to Link section

Hace algunos años conseguí mi primera certificación – Salesforce Force.com Developer, también conocida como Dev 401. Así que cuando supe que ya no estaba disponible y (peor aún) que en breve dejaría de tener validez, casi me echo a llorar. Pero Salesforce nos ofrece una forma de conseguir una certificación equivalente, App Builder, de forma sencilla mediante un examen de transición.

Captura de pantalla 2017-03-10 a las 12.11.07

¿Cómo es este examen de transición?

Tienes 30 minutos para contestar 20 preguntas tipo test dónde la respuesta puede ser 1 ó varias opciones. Debes tener en cuenta que para conseguirlo necesitas una puntuación del 65%. 

Como en otros exámenes, puedes hacerlo en una localización de Salesforce, ó en casa vigilado por el programa Centinela.

Si sólo tienes esta certificación, el examen de transición es gratuito para ti. Bueno, eso creo. Yo tenía Dev 501 y mi transición para el Platform Developer I & II fue gratuito. Sin embargo para éste tuve que pagar los 100USD reglamentarios. Por eso creo que Salesforce te deja un examen de transición gratuito. Y tienes 3 oportunidades para aprobar. Si no lo consigues, volver a intentarlo cuesta 50USD.

 

¿Consejos para estudiar?

Via webassessor puedes registrarte y bajarte el material de referencia dónde encontrarás los puntos más importantes y conocimientos que se esperan para esta certificación.

Captura de pantalla 2017-03-10 a las 12.29.50.png

La verdad es que este examen me ha resultado más fácil ya que para el transition del Platform Developer I & II la guía te pedía que estudiaras lo mismo que para los dos exámenes así que le dediqué muchísimo tiempo.

En esta ocasión con los enlaces de la imagen de arriba (no he puesto los enlaces directamente por si de una versión a otra cambia algo. Ve a la guía y revísalo) y alguna información extra encontrada en blogs, tuve más que de sobra.

Soy de la vieja escuela, así que después de imprimir el material y subrayarlo, dedicaba 1 ó 2 horas al día a repasar la teoría y hacer alguno de los mocks exam que encontré por la red (más abajo tienes los enlaces)

El día del examen

La vin compae qué complicado es hacerte la foto para empezar el examen. Entre lo blanca que soy y que milagrosamente era un día bastante soleado en Bilbao, mi cara tenía bastante luz y nada, no había forma. 

Esta anécdota es sólo para recordarte que prepares el sitio del examen con antelación. Cuando te registras te llegará un email con información sobre los requisitos de software y hardware necesarios para el examen. Y aun así, si tienes problemas después de lanzar el examen, respira hondo que al final lo conseguirás.

Tardé unos 15 minutos en pasar todas las preguntas, por lo que tuve 10 más para una segunda vuelta, y 5 para aquellas preguntas con las que tuve más dudas. Pero en principio tienes tiempo suficiente.

Encontré preguntas sobre:

  • Record Types
  • Tipos de relaciones entre objectos
  • External Objects
  • Cambios de tipo de campos. Por ejemplo, ¿se puede de currency a number sin perder información?
  • Field Updates
  • Orden de ejecución de triggers. En realidad eran preguntas relacionadas con field updates pero que si sabes el orden de ejecución de los triggers, puedes responderla sin problemas.

Últimos consejos

Asegúrate de estudiar con el material de la release para la que te vas a examinar. De una a otra no suele cambiar demasiado, pero por si acaso.

Intenta usar cable de red en vez de wifi. Cualquier corte inesperado puede parte el examen … qué gracia.

Apaga el móvil. La vibración también distrae.

Respira hondo. Si yo lo he conseguido tu también.

Si has visto en alguna web que por un precio simbólico te ofrecen más exámenes de prueba, sinceramente creo que para este examen no es necesario pero seguro que también es útil.

Links

Este es el material que revisé además de el proporcionado por la guía.

¡Aviso a navegantes! Intenta descargar de alguna manera los mocks exams ya que durante mis dos semana de estudio, algunos enlaces dejaron de funcionar.

Mi guía de estudio pero usa la última versión via webassessor.

Flash cards ¡muy útiles!

Más Flash cards pero más orientadas al examen App Builder que al Transition.

Sample Questions

Blog y blog Información extra interesante.

¡Suerte!

 

My First Lightning Component on Utility Bar via Eclipse

Note: I wrote this post in October 2016 but didn’t publish it because I was getting issues trying to making Eclipse work. However, after few months and do not find a solution, I decided to publish what I wrote. Maybe first steps could help others. An if you have the answer to my issue, I would really appreciate your help.

In addition I have included a super simple Lightning Component and how to integrate in the new Utility Bar that Spring ’17 bring to us.

When you develop some code, which is the tool you use for it? If you have never created some complex line of code, maybe you think that Developer Console allows you to do what you need. However, if your daily basis is programming, you need a tool outside of the org for that.

Nowadays I use Mavensmate, but on my early days I was an Eclipse fan, so when I knew that there is a beta version of Force.com IDE in order to create Lightning Components, I decided I had to check it. And this post is about it. Well, more about how to install it, as well as create a super simple Lightning Component.

First of all, I tried to open my Eclipse and create a project againts my org. But I got this error:

captura-de-pantalla-2016-10-08-a-las-12-18-48

Oh my God!! It’s true that long time ago since I don’t open Eclipse (Juno in my case) !!! So first of all, fix it. How? Here there is a link that explain you about this Salesforce change, but here is what I did on my Mac.

  1. Run java -version on cmd — old version as well !! So via System Preferences, click on Java icon and updated the version to 8 one there. And also download latest JDK.

Now java -version returned to me 8 one. So I tried again and this time it worked.

However I tried to install Force.com IDE for lightning and I got an error, so checked more instructions and I found this article and I realized that my version was older than 4.5, so decided to download a newer version. If this is not your case, jump next section

How to install eclipse

From here you can download latest Eclipse version (be sure you get it for Mac or PC depending on your machine OS). Well, actually you download an installer. When I executed it, I got an error message, so after looking at several blogs, like this one, I realized that I had to update the installer via the top right coner icon.

captura-de-pantalla-2016-11-11-a-las-14-20-53

Then just select Eclipse IDE for Java Developers and click on install. Again I got an error with Neon, so I decided to try with another Product which version is higher than 4.5, so I chose Mars

Captura de pantalla 2016-11-22 a las 17.16.09.png

How to install Force.com IDE

The installation is quite straight forward, you just need to follow below steps (find also the information here)

  1. In Eclipse, click Help > Install New Software.
  2. Add this new update site: https://developer.salesforce.com/media/force-ide/beta_eclipse45
  3. Be sure that Group items by category checkbox is not selected.
  4. Select the checkbox next to Force.com IDE (required).
  5. If you have Apex Debugger licenses, select the checkbox next to Force.com IDE Debugger.
  6. Select the checkbox next to Force.com Lightning Support
  7. Click Next and start the installation.

20170203 Note There is new link to Eclipse IDE because it is no beta anymore as well as you can also find more information on Salesforce page as well. I tried with them as well, but no luck, still does not work.

How to work with Eclipse

Now you can create the project as usual, but you will realize that the folder structure looks different. It also have the aura folder. If we want to add / create the aura element we will find the entry as well.

How to create a Lightning Component

As you can find lot of information related to Lightning Components creation (including Trailheads) I will not explain in deep what it is a Lightning Component and how to create it. Just show you how you can develop something super simple in Eclipse.

Use Case – Employee List

I have a custom object, Employee, in my organization

Captura de pantalla 2016-11-23 a las 10.49.10.png

And I would like to create a Lightning Component that list all my Employees and be able to insert on the Home tab, for instance.

20170203 Note: I was not able to make Eclipse work, so this code has been developed in Salesforce Developer Console. Do you want me to help anyhow and get some credits? Find my question on stackExchange as well as Developer Forums

Super simple Employee List Lightning component

I will create 2 component.

The first one will just show the FirstName and Surname of an Employee

<!-- EmployeeListItem -->
<aura:component>
    <aura:attribute name="employee" type="Employee__c"/>
    <li>{!v.employee.FirstName__c}{!v.employee.Surname__c}</li>
</aura:component>

And the second one will iterate over a list of Employees and make calls to the above component in order to show the information.

<!-- EmployeeList -->
<aura:component controller="EmployeeController" 
                implements="flexipage:availableForAllPageTypes">
    <aura:attribute name="employees" type="Employee__c[]"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <h3>Employees</h3>
    <aura:iteration items="{!v.employees}" var="empl">
       <c:EmployeeListItem employee="{!empl}"/>
    </aura:iteration>
</aura:component>

But for that, it needs to retrieve the information somehow. That’s why we have the reference to the server side controller EmployeeController.

/**
* @agarciaodeian
**/

public with sharing class EmployeeController
{
    @AuraEnabled
    public static List<Employee__c> getEmployees()
    {
        List<Employee__c> listRetrieved = new List<Employee__c>();        
        if(Schema.sObjectType.Employee__c.isAccessible())
        {
               listRetrieved = [SELECT Id, Name, FirstName__c, 
                                       Role__c, Surname__c 
                                FROM Employee__c];
        }
        return listRetrieved;
    }
}

Finally, in order to get the result, in the EmployeeList we execute the action that initialize the list of employees making a call to the JavaScript controller

({
    doInit : function(component, event) {
       var action = component.get("c.getEmployees");
       action.setCallback(this, function(a) {
          component.set("v.employees", a.getReturnValue());
        });
        $A.enqueueAction(action);
    }
})

Once I have the code in the organization, I can create a project on Eclipse and I would see my components under the aura folder

captura-de-pantalla-2017-02-04-a-las-11-42-36

If I open EmployeeList, for instance, I can see also the EmployeeListController.js tab as well. So it is easier and it is sorter than in the Developer Console.

How to add my Lightning Component to the Utility Bar

captura-de-pantalla-2017-02-04-a-las-11-57-11

 

 

 

Once I have the Lighting Component, I can show the result in the Home page tab for instance

 

 

 

And now that Spring ’17 is arriving, we can include also our lighting components into the Utility Bar. Previously we had to create it via metadata and deploy but now it’s a matter of point and clicks.

Go to App Manager and edit your app. Now, one of its steps is the Utility Bar  and after clicking on Add button you can find same Lightning Components than in the App Builder.

captura-de-pantalla-2017-02-04-a-las-15-32-54

For instance, standard like Flow (Beta), Manage, and Custom. So I select my custom lighting Component Employee List.

And … that’s all!! Now I have my super simple LC in the Utility Bar, so that I can see the list of all Employees from everywhere, including Salesforce Setup page.

captura-de-pantalla-2017-02-04-a-las-15-36-51

Lightning Experience and Visual Flow

Today I’m going to do some researches with one of these #clicksnotcode features that Salesforce provides in the Platform, Visual Flow. Ok, this is not a hot topic now, but if we want to check how it works in Lightning Experience (LEX from now onwards) then, this post could be a bit more interesting for you.

Take into account that Visual Flow in LEX is in beta

The use case it’s simple. I have a Hotel, and I would like to get some feedback from my guests, so I will send them a survey.

The Flow would be very simple, and as the creation is not the main goal here, I will not show it step by step. But if you are new, double check Visual Flow documentation and also TrailHead.

First of all we need to open Flow Designer, so, can I do it in LEX? Yes. Go to Setup and just write “flow” in order to find it and be able to open this platform feature.

captura-de-pantalla-2016-12-02-a-las-10-35-11

As you can see on below image, the Flow Designer looks like the Classic UI one, so you would not need to learn how to work with it if you already used it.

captura-de-pantalla-2016-12-02-a-las-12-08-29

Once I have created my Flow, we can add it to our Home page, but remember to Activate it, otherwise it would not be available in Lightning App Builder.

So, go to Home, Edit this page, and Lightning App Builder will help you to add it there.

How? Really simple, if you go to Standard Apps, one of them is Flow (beta) so you only need to click on it, and your flow will appear in the home page.

captura-de-pantalla-2016-12-02-a-las-10-57-11

But actually I have 2 active flows, so what can I do? When you highlight your custom Flow, on the right side you have the option to select the one you need to show, so just pick one.

captura-de-pantalla-2016-12-02-a-las-11-12-38

I can also say that I had to try a couple of times till I got this behavior. First time, Book Room flow did not appear on the drop down list, so there were not way to add it to my Home page. But remember, this feature is on beta, so be patience and try till you get it.

Last thing to mention is the fact that you can chose between 1 or 2 columns. My first thought was that this attribute would help me to determine if I wanted 2 flows on the same row on the page layout, but it is not related to that. It just help you to set all your flow fields in 2 columns instead of one. For instance, these 2 screens show same fields but they are sorted in a different way.

captura-de-pantalla-2016-12-02-a-las-12-11-41captura-de-pantalla-2016-12-02-a-las-12-11-08

And how it works? In Spanish we say better a image rather than thousand words but in this case, better a video rather than thousand images.

 

Maybe your last question is if we can add it to any other place? Yes, for instance, I can include it in my Guest record layout

captura-de-pantalla-2016-12-02-a-las-13-06-23

But let’s make up a little bit and define something for every guest:

captura-de-pantalla-2016-12-04-a-las-20-20-05

In order to do that, I had to add a Lookup step in the Flow and use the variable {!recordId} as a filter. So that, I can retrieve Guest object record and use it in my Flow.

captura-de-pantalla-2016-12-04-a-las-20-26-44

It was not easy to find the way to retrieve the recordId but this post helped me a lot.

I hope you liked this short entry about Flow. You can find more information on Salesforce release notes entry.

 

 

 

Maps and Visualforce

Since I was checking Force.com documentation in order to pass Platform Developer Transition exam I had the opportunity to learn more about some topics that I don’t usually use on my daily job.

One of those are Maps, and I’m not talking about Collections (Lists, Sets and Maps). I would like to talk about locations on this post.

Till some releases ago, the only way to add a location into your visualforce page, was via JavaScript. Let’s see an example. (Bellow use case is based on this Salesforce Trailhead)

I’m working on a healthcare app, and we would like to show a map on every doctor’s record, so that, the customer would be able to find the location easily.

In order to get it, I will create a visualforce page with the map and include it in the standard layout.

JavaScript Map Version

First thing is to add the listener:

 google.maps.event.addDomListener(window, 'load', initialize);

that call an initialize function

 var map;
 
 function initialize() {
     var mapOptions = {
         center: new google.maps.LatLng(43.2616465, -2.9393368),
         zoom: 15
     };
     map = new google.maps.Map(document.getElementById("map-canvas"), 
                               mapOptions);
     loadDoctor();
 }

Where we define map properties, like latitude, longitude and zoom.

But this function call another, loadDoctor 

 function loadDoctor()
 {
     Visualforce.remoting.Manager.invokeAction(
         '{!$RemoteAction.DoctorsController.findTheDoctor}',
         '{!Id}',
         function(result, event)
         {
             if (event.status) {
                 var name = result.SurgeryName__c;
                 var lat = result.Location__Latitude__s;
                 var lng = result.Location__Longitude__s;
                 addMarker(name, lat, lng);
             } else {
                 alert(event.message);
             }
        },
        {escape: true}
     );
 }

Above function uses a RemoteAction method, so we know that a Controller is included on this page. This communication with the controller just returns information about the Doctor’s records like his place name and the Location. Maybe you are wondering what below line means.

Location__Latitude__s  and  Location__Longitude__s

Location is a Geolocation field, and, in the end, it is a Compound field, so in order to see the information, we need to decouple into its “elements”, Latitude and Longitude.

Finally, on above method, we have a call to another function that will add the marker on the google map

 function addMarker(name, lat, lng)
 {
     var marker = new google.maps.Marker
           ({
               position: new google.maps.LatLng(lat, lng),
               map: map,
               title: name
           });
 }

With this code, the result is this one:

Captura de pantalla 2016-07-30 a las 22.17.58

Apex Map Version

Is there a different way to get the same result? Yes !! Since Spring ’15 we have a new tag available on visualforce pages: apex:map and with this piece of code:

<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                    position="{!Doctor__c.Location__Latitude__s},
                              {!Doctor__c.Location__Longitude__s}">
    </apex:mapMarker>
</apex:map>

we can get exactly what we had on the javascript code as we can see on below image that compares both maps. Left side uses apex:maps whereas on the right side the map is created with javascripts.

Captura de pantalla 2016-07-30 a las 22.24.42

More about apex:map

Attributes

  • Height and Width could be defined as pixels or percentage
  • Center could be used with Location data, Address and also with JSON format. From my point of view, it would be easier to create a method in the controller with the data
public Map<String,Double> getDoctorsCenter()
{
    Map<String,Double> mapCenter = new Map<String,Double>
                                   {
                                      'latitude' => 43.2616465,
                                      'longitude' => -2.9393368
                                    };
    return mapCenter;
}

and use the method in the visualforce page.

<apex:map width="100%" height="100%" mapType="roadmap" 
          zoomLevel="15"
          center="{!doctorsCenter}">

Above example set geolocation with hardcode but if we have this information on data base, the code could be safer and don’t fail if there is any change on this data.

MapMarker

  • Similar as before, position attribute could be defined based on Address, JSON or using the Geolocation field. On above example, we directly used the compound sub-fields, but it would be also fine to get this information in the controller, create the map and call the method in the page as we show on center attribute.
  • If your idea is to show all doctors around your city, instead of adding an mapMarker per record, remember to use apex:repeat tag
<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:repeat value="{!locations}" var="pos">
        <apex:mapMarker position="{!pos}"/>
    </apex:repeat>
</apex:map>
  • Another mapMarker attribute is icon that help us to show a different image than the red bubble that google offer to us. A good way to show it is using a static resource and make a call to it.
<apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                position="{!Doctor__c.Location__Latitude__s},
                          {!Doctor__c.Location__Longitude__s}"
                icon="{!URLFOR($Resource.MapMarkers, 'myIcon.png')">
</apex:mapMarker>

MapInfoWindows

  • This is another tag to show even more information. So for instance, below code show the doctor’s name and phone if we click on the marker icon
<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                    position="{!Doctor__c.Location__Latitude__s},
                              {!Doctor__c.Location__Longitude__s}">
        <apex:mapInfoWindow >
            <apex:outputPanel layout="block" style="font-weight: bold;">
                <apex:outputText >{!Doctor__c.SurgeryName__c}
                </apex:outputText>
            </apex:outputPanel>
            <apex:outputPanel>
                <apex:outputText >{!Doctor__c.Phone__c}
                </apex:outputText>
            </apex:outputPanel>
        </apex:mapInfoWindow>
    </apex:mapMarker>
 </apex:map>

 

Captura de pantalla 2016-08-02 a las 17.58.24.png

JavaScript vs apex:map

  1. Unfortunately, we cannot create a page with map tag in a Developer Edition, however JavaScript is available on Developer editions. But if you want to give it a try, create your own Trial edition.
  2. As JavaScript is executed on the client side, the map is loaded quicker than the one that use apex:map.
  3. On the other side, Salesforce takes care of any apex tag so any change on code versions, or browser, etc. that could make the code fail, Salesforce will deal with it.
  4. JavaScripts needs a method in the controller in order to get Location information dynamically and if we want to show the map inside a Standard layout, we must define the RemoteAction method as global that makes you define the class as global as well. This is not important till you add the code inside a package. As a reminder, global classes are available to everybody that install your package and maybe this is not your desire.
  5. RemoteAction is not able to get parameters from url. So I cannot do something like
Id currentDoctorId = controller.getId()

and then use it on the RemoteAction method. However,  in our case, we can use directly the Id of the record on the visualforce page as a workaround:

Visualforce.remoting.Manager.invokeAction(
         '{!$RemoteAction.DoctorsController.findTheDoctor}',
         '{!Id}',
         function(result, event){....});

Resources

  1. Apex:map Salesforce documentation
  2. Github Repository with code used on above examples

Mi primera Visualforce IV – Controladores II

¡Cuánto tiempo! Pues si, en Enero fue mi último post en Español y 11  meses después vuelvo a escribir una entrada en nuestra lengua materna. Y es que últimamente he estado un pelín ocupada con mi bebe de 7 meses.

Esta será la última entrada con el título Mi primera Visualforce ya que terminaremos de cubrir conocimientos básicos. Pero no significa que no seguiré escribiendo en Español. Seguid atentos porque publicaré cosas.

¡Pero vamos al lío! Todos los objetos tienen asociados un controlador estándar que le proporciona funcionalidad (Échale un vistazo a esta entrada). Además, podemos crear controladores personalizados para extender y dar más potencia a nuestra página.

Además los controladores pueden tener un único elemento como argumento, como expliqué en mi última entrada, ó a una lista de registros.

Controlador asociado a varios registros

 

Controlador Estándar

Como recordarás, para usar el controlador estándar, sólo tienes que usar el atributo standardController del tag apex:page

<apex:page standardController="Account">
</apex:page>

Entonces, ¿cuál es la diferencia? Como supondrás, necesitaré una variable para poder almacenar todas las cuentas, y después iterar sobre ella. Para ello, apex:page ofrece otro atributo recordsetVar cuyo valor será la lista de registros. Una vez que la tengamos, sólo tenemos que mostrar los campos que deseemos de nuestra cuenta. En el código de más abajo, usaremos el tag apex:repeat aunque podríamos haber usado también apex:datatable como en posts anteriores.

<apex:page standardController="Account" recordsetVar="records">
   <apex:form >
      <apex:pageBlock title="Listado de Cuentas">
         <apex:pageBlockSection columns="1">
            <apex:repeat value="{!records}" var="acc">
               <apex:outputField value="{!acc.Name}"/>
            </apex:repeat>
         </apex:pageBlockSection>
      </apex:pageBlock>
   </apex:form>
</apex:page>

Siendo este el resultado

Captura de pantalla 2016-11-07 a las 18.52.19.png

Controlador Personalizado

¿Y cómo puedo conseguir lo mismo pero con un controlador creador por mi mismo? Sólo tienes que seguir estos pasos:

Crear un Controlador en Apex

Una clase en Apex sencilla. Pero ten en cuenta lo que explicamos en el último post sobre nomenclatura, sharings, etc. Lo único que debemos tener en cuenta es el constructor. Esta vez, en vez de utilizar ApexPages.StandardController, usaremos la clase ApexPages.StandardSetController que nos permitirá recuperar la lista de registros seleccionados (por ejemplo) con el método getRecords de forma similar que el controlador de único registro nos ofrecía el método getRecord. Pero además, en este caso, tenemos métodos para facilitar la paginación cómo getHasNext ó getHasPrevious.

public with sharing class AccountListController
{
   public AccountListController(ApexPages.StandardSetController controller)
   {
      //TODO añadir código
   }
}

Añadir método para recuperar la lista de cuentas

Muy sencillo. Añadimos la variable registroCuentas con sus métodos get y set. Por otro lado, añadimos un método que recuperará las listas que tenemos en base de datos por medio de una SOQL calcularCuentas. Y por último, en el constructor, rellenamos la variable privada con la información.

public with sharing class AccountListController
{
   private List<Account> registroCuentas;
 
   public AccountListController(ApexPages.StandardSetController controller)
   {
      setRegistroCuentas(calcularCuentas());
   }
 
   public List<Account> calcularCuentas()
   {
      try
      {
         return [Select Id, Name From Account];
      }
      catch(Exception ex)
      {
         ApexPages.addMessages(ex);
         return null;
      }
   }
 
   public List<Account> getRegistroCuentas()
   {
      return registroCuentas;
   }
 
   public void setRegistroCuentas(List<Account> value)
   {
      registroCuentas = value;
   }
}

Modificar la página para usar el Controlador

En este último paso sólo tenemos que añadir el atributo extensions cuyo valor es el nombre del controlador personalizado que hemos creado. Además, debemos usar nuestro método como valor en el atributo recordSetVar.

<apex:page standardController="Account" 
           extensions="AccountListController" 
           recordsetVar="registroCuentas">
   <apex:form >
      <apex:pageBlock title="Listado de Cuentas Personalizado">
         <apex:pageBlockSection columns="1">
            <apex:repeat value="{!registroCuentas}" var="acc">
               <apex:outputField value="{!acc.Name}"/>
            </apex:repeat>
         </apex:pageBlockSection>
      </apex:pageBlock>
   </apex:form>
</apex:page>

captura-de-pantalla-2016-11-07-a-las-19-23-30

Como puedes ver, el look & feel de la página es igual que la página que usa el controlador estándar.

A partir de ahí, eres tu quien pone los límites en una página.

Alternativa

Por último, si nuestro caso de uso es simplemente mostrar la lista de Cuentas, pero no nos piden nada más (por ejemplo mostrar sólo unos campos), podemos usar el tag apex:enhancedList y no reinventar la rueda. Con esta línea de código, podemos mostrar todas las cuentas de nuestra organización junto con sus enlaces de editar, borrar, seleccionar, etc y sin ningún esfuerzo.

<apex:page >
   <apex:enhancedList type="Account" 
                      height="300" 
                      rowsPerPage="10" 
                      id="AccountList" />
</apex:page>

 

captura-de-pantalla-2016-11-08-a-las-17-45-17

Esta ha sido una entrada sencilla en la que hemos aprendido

  • Mostrar una lista de Cuentas por medio del controlador Standard
  • Mostrar una lista de Cuentas via un controlador personalizado
  • Mostrar una lista de Cuentas usando el tag apex:enhancedList 

Nos vemos en el próximo post.