Skip to main content

Modification de l’application native Forcedroid

Objectifs de formation

Une fois cette unité terminée, vous pourrez :

  • Modifier l'application modèle Android native pour personnaliser l'écran de la liste
  • Traiter une réponse REST
  • Supprimer un enregistrement Salesforce via une requête REST

Personnalisation de l'écran de la liste

Comme vu précédemment, l’application modèle Android native affiche une liste de contacts et de comptes depuis l’organisation Salesforce de l’utilisateur. Actuellement, cette liste en lecture seule est générée à partir d’une simple requête SOQL SELECT traitée par les classes REST du kit de développement Mobile SDK. Ajoutons quelques capacités de modification en associant une action de suppression en cas de pression longue. Lorsque l’utilisateur touche et maintient un nom de contact dans la vue de liste, votre nouvelle action de suppression tente de supprimer l’enregistrement Salesforce associé. Si cette tentative réussit, votre application supprime définitivement la ligne de la vue de liste Contacts dans l'application. Si la requête échoue, votre application indique à l'utilisateur les raisons de cet échec et rétablit la ligne de la vue de liste.

À propos du module d'écoute du clic prolongé

L’implémentation de ce module est simple. Mais décider comment créer une classe pour le module d'écoute du clic prolongé est un peu plus délicat. Si vous explorez les différentes options de codage, la première chose que vous découvrirez, c'est que vous ne prêtez pas attention aux clics au niveau de la vue de liste. Vous le faites au niveau des éléments de la liste. Par chance, implémenter des modules d'écoute pour les éléments de la liste n'est pas une tâche difficile, grâce à l'interface Android OnItemLongClickListener. Cette interface définit un seul module d'écoute associé à la vue de liste et répond aux pressions longues sur un élément de la liste. Vous créez une instance de cette classe en implémentant une interface publique au sein de votre classe de vue.

Le prochain défi est de déterminer la classe de vue qui implémente le module d'écoute du clic prolongé. Grâce aux objets ListView, vous fournissez un objet de données qui donne les informations qui s'affichent dans la liste. L’application modèle du kit de développement Mobile SDK crée, dans cette optique, un objet ArrayAdapter<String>, puis le rattache à ListView.

listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new 
ArrayList<String>());
((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);

Mais ArrayAdapter<String> est un objet de données, pas une vue, exact ? Oui, mais pas seulement. Dans la vue de liste Contacts, ArrayAdapter crée un objet AdapterView pour chaque élément de l'ensemble des données de la liste. Les vues de cet adaptateur représentant les objets qui vous intéressent. Par conséquent, utilisez la classe AdapterView pour implémenter OnItemLongClickListener. Vous associez ensuite l'objet du module d'écoute à l'objet ListView, qui reçoit toutes les notifications pour ses enfants. Cette association limite votre OnItemLongClickListener pour qu'il interagisse uniquement avec les éléments de la vue de liste de l'application modèle. Enfin, vous exécutez votre comportement de suppression dans la seule méthode d'interface.

Un dernier détail à résoudre : où placez-vous ce code pour le module d'écoute du clic prolongé ? Le kit de développement Mobile SDK vous propose les méthodes de rappel de point d’entrée suivantes :

public abstract void onResume(RestClient client);
@Override
protected void onCreate(Bundle savedInstanceState);
@Override 
public void onResume();

Nous pouvons en éliminer une : onCreate (Bundle savedInstanceState). Cette méthode configure l'activité et gère les flux d'authentification avant l’instanciation des vues. Les vues entrent en action dans la méthode onResume(). Cette méthode semble donc être la plus probable. La méthode onResume(RestClient client) est appelée par la super-classe lors de la connexion pour capturer l’objet RestClient authentifié, que nous allons laisser de côté ici. Par conséquent, les résultats sont arrivés. Ajoutez votre code d’écoute du clic prolongé à onResume().

Implémentation d'un module d'écoute de clic prolongé de base

Commençons à coder. Dans Android Studio, ouvrez votre classe MainActivity et observez la méthode onResume().
  1. Dans Android Studio, ouvrez votre fichier MainActivity.java.
  2. Recherchez la méthode onResume().
    @Override 
    public void onResume() {
        // Hide everything until we are logged in
        findViewById(R.id.root).setVisibility(View.INVISIBLE);
    
        // Create list adapter
        listAdapter = new ArrayAdapter<String>(this, 
            android.R.layout.simple_list_item_1, new ArrayList<String>());
        ((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);			
        // ADD CODE HERE!
        super.onResume();
    }
    Nous allons commencer le codage comme indiqué, après la configuration de listAdapter pour ListView, mais avant l'appel super.onResume().
  3. Déclarez et attribuez une variable pratique ListView qui référence la vue de liste Contacts. Utilisez la méthode Activity.findViewById() pour référencer la ressource de la vue de liste.
    ((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);	
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    super.onResume();
  4. En utilisant la variable lv, appelez la méthode AdapterView.setOnItemLongClickListener() pour configurer un écouteur d’événements de clic prolongé. Pour le paramètre de l’écouteur, instanciez un stub en ligne de l’interface AdapterView.OnItemLongClickListener.
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    lv.setOnItemLongClickListener(
        new AdapterView.OnItemLongClickListener() {
            @Override
    	 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                return false;
            }
        });
    
    Remarquez qu’Android Studio insère même la méthode d’interface virtuelle unique pour vous. Pratique !
  5. (Facultatif ) Si vous obtenez une erreur d’importation manquante, ajoutez import android.widget.AdapterView à vos importations de classe.
  6. Dans le corps AdapterView.OnItemLongClickListener, remplacez l’instruction return standard par le code qui présente un message de confirmation.
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    lv.setOnItemLongClickListener (new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,
            int position, long id) {
            Toast.makeText(getApplicationContext(),
                "Long press received", Toast.LENGTH_SHORT).show();
            return true;
            }
    });
  7. Compilez l’application, puis exécutez-la.
  8. Lorsque vous êtes connecté à l’application, cliquez sur Fetch Contacts.
  9. Touchez une entrée dans la liste Contacts et maintenez appuyé pendant quelques secondes. Si tout est correct, le message toast s’affiche.

Ajout de requêtes REST du kit de développement mobile

Vous allez bientôt pouvoir ajouter des éléments du kit de développement Mobile SDK. Dans la méthode onItemLongClick(), vous créez une requête REST pour supprimer l’enregistrement Salesforce associé à la ligne touchée. Vous envoyez ensuite cette requête à Salesforce. Avant d’explorer le code, examinons quelques points importants.

Obtention d’une instance RestClient

N’oubliez pas que vous ne créez jamais directement des objets RestClient. Le kit de développement Mobile SDK en crée un pour vous et le renvoie à MainActivity via la méthode onResume(RestClient client). Cette instance RestClient est authentifiée avec le jeton d’accès de l’utilisateur actif. Pour votre utilisation, la méthode onResume(RestClient client) attribue cette instance à la variable de classe client.

Création d’une requête REST

Pour créer la requête REST de cet exercice, vous appelez la méthode d’usine RestRequest pour supprimer un enregistrement :

public static RestRequest getRequestForDelete(String apiVersion, String objectType, String objectId);

Où trouver les valeurs d'argument ? Examinez le tableau ci-dessous.

Paramètre Valeur
apiVersion Défini dans les ressources de votre application : getString(R.string.api_version)
objectType « Contact » (codé en dur)
objectId ??
Le paramètre objectId pose problème. Il nécessite une valeur Salesforce que votre application forcedroid brute ne reconnaît pas. Pourquoi ne l'avez-vous pas ? Que pouvez-vous faire pour l'avoir ? Les réponses sont simples :
  • Vous n'avez pas les ID, car les requêtes REST d'origine (celles de la liste) ne les demandent pas.
  • Vous pouvez obtenir l'ID en modifiant les requêtes REST.

Ajustement de la requête SOQL du modèle d’application

Votre classe MainActivity émet deux requêtes REST : une pour les contacts et une autre pour les comptes. Chaque requête contient une instruction SOQL. Nous allons utiliser des comptes. Par conséquent, mettez à jour la requête des enregistrements Contact pour renvoyer les valeurs d’ID.

  1. Dans Android Studio, ouvrez le fichier MainActivity.java.
  2. Recherchez la méthode onFetchContactsClick().
    public void onFetchContactsClick(View v) throws UnsupportedEncodingException
    {
       sendRequest("SELECT Name FROM Contact");
    }
    
  3. Changez la requête SOQL pour sélectionner les champs Name et Id. Assurez-vous de respecter la casse mixte du nom de champ de l'ID. Les noms de champs sont sensibles à la casse.
    public void onFetchContactsClick(View v) throws UnsupportedEncodingException
    {
       sendRequest("SELECT Name, Id FROM Contact");
    }

Vous êtes prêt à recevoir les valeurs d’ID dans la réponse REST. Quel est le meilleur emplacement pour les stocker ? L'application modèle copie simplement la valeur Nom de chaque enregistrement dans une ligne de la vue de liste, elle ne met en cache les valeurs d’ID. Pour activer les références dans votre gestionnaire, vous devez stocker les ID dans une portée de classe.

Adaptation de la méthode sendRequest() de l'application modèle

Faites défiler jusqu'à la méthode sendRequest(String soql), qui correspond à l'endroit où arrivent les réponses d'extraction. Cette méthode démontre clairement la façon dont fonctionne le mécanisme REST du kit de développement Mobile SDK. Jetons-y un rapide coup d'œil. Tout d'abord, la méthode appelle une méthode de fabrique RestRequest, qui définit une requête REST pour une requête SOQL donnée :
RestRequest restRequest = RestRequest.getRequestForQuery(
    ApiVersionStrings.getVersionNumber(this), soql);

Elle envoie ensuite le nouvel objet RestRequest à Salesforce dans l’appel client.sendAsync().

client.sendAsync(restRequest, new AsyncRequestCallback() {
    @Override
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly(); // consume before going back to main thread
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    listAdapter.clear();
                    JSONArray records = result.asJSONObject().getJSONArray("records");
                    for (int i = 0; i < records.length(); i++) {
                        listAdapter.add(records.getJSONObject(i).getString("Name"));
                    }
                } catch (Exception e) {
                    onError(e);
                }
            }
        });
    }
 
    @Override
    public void onError(final Exception exception) {
        runOnUiThread(new Runnable() {
        @Override
            public void run() {
                Toast.makeText(MainActivity.this,
                    MainActivity.this.getString(
                        R.string.sf__generic_error, 
                        exception.toString()),
                    Toast.LENGTH_LONG).show();
            }
        });
    }
});

En plus de l’objet RestRequest, l’appel sendAsync() nécessite d’implémenter l’interface AsyncRequestCallback du kit de développement Mobile SDK. La méthode onSuccess() de cette interface reçoit la réponse REST de façon asynchrone via un rappel. Votre implémentation par défaut AsyncRequestCallback traite uniquement les requêtes SOQL définies dans votre application forcedroid.

Cette méthode onSuccess() fait déjà ce dont nous avons besoin. Elle contient le code qui extrait les enregistrements renvoyés par la réponse REST et les attribue à la variable locale records. Déplaçons cette variable vers l’étendue de la classe en la redéclarant hors du corps de la méthode.
  1. En haut de la définition de la classe MainActivity, déclarez JSONArray records en tant que variable privée avec les déclarations de la variable de classe existante :
    public class MainActivity extends SalesforceActivity {
        private RestClient client;
        private ArrayAdapter<String> listAdapter;
        private JSONArray records;
       ….
  2. Dans la méthode onSuccess(), supprimez la déclaration de type de la variable records :
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly(); // consume before going back to main thread
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    listAdapter.clear();
                    records = result.asJSONObject().getJSONArray("records");
                    for (int i = 0; i < records.length(); i++) {
                        listAdapter.add(records.getJSONObject(i).getString("Name"));
                    }
                } catch (Exception e) {
                    onError(e);
                }
            }
        });
    }

Épilogue de la méthode onItemLongClick()

Voici l'épilogue de la méthode onItemLongClick(). L’algorithme de base est le suivant :

  1. Obtenir un objet de « demande de suppression » en appelant une méthode de factory appropriée du kit de développement Mobile SDK, RestRequest. Toutes les méthodes RestRequest renvoient des exceptions, assurez-vous donc de placer l'appel dans un bloc try...catch.
  2. Envoyer l’objet de « demande de suppression » à Salesforce à l’aide de l’objet généré RestClient.
  3. Traiter le résultat REST dans les méthodes de rappel.

Obtention d'un objet RestRequest

  1. Revenez à la méthode onItemLongClick() dans la méthode onResume().
  2. Après l'appel Toast.makeText(), déclarez un objet local RestRequest nommé restRequest. Initialisez-le sur null.
    RestRequest restRequest = null;
  3. Ajoutez une construction vide try...catch.
    RestRequest restRequest = null;
    try {
    
    } catch (Exception e) {
     
    }
  4. Dans le bloc try, appelez une méthode de fabrique qui obtient un objet de requête REST pour l'opération de suppression. ASTUCE : Utilisez la méthode statique RestRequest.getRequestForDelete().
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
                   // arguments?
                );
    } catch (Exception e) {
     
    }
  5. Pour le premier paramètre, récupérez la version de l’API Salesforce spécifiée dans les ressources Kit de développement mobile de votre projet.
    RestRequest restRequest = null;
    try {
         restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), //...);
    } catch (Exception e) {
    
    }
  6. Pour le paramètre objectType, spécifiez « Contact ».
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact", //...);
    } catch (Exception e) {
    
    }
  7. Transmettez à RestRequest.getRequestForDelete() l'ID de l'entrée dans le tableau des enregistrements qui correspond à la position actuelle de la vue de liste. Voici comment récupérer l'ID :
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact",
            records.getJSONObject(position).getString("Id"));
        // Send the request
        // ...
    } catch (Exception e) {
    
    }
  8. Dans le bloc catch, appelez printStackTrace() sur l'argument Exception.
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact",
            records.getJSONObject(position).getString("Id"));
        // Send the request
        // ...
    } catch (Exception e) {
        e.printStackTrace();
    }

Dès que vous avez obtenu l’objet « requête de suppression », envoyez-le à Salesforce, puis gérez le résultat dans les méthodes de rappel.

Ajout de la méthode RestClient.sendAsync()

Vous y êtes presque ! La dernière étape consiste à envoyer la requête à l'aide de la méthode RestClient.sendAsync(). Cette méthode nécessite d’implémenter l'interface AsyncRequestCallback. Comme vous le savez, le kit de développement Mobile SDK envoie les réponses REST à vos méthodes AsyncRequestCallback.

  1. Dans onItemLongClick(), après l’appel getRequestForDelete(), copiez et collez le code RestClient.sendAsync() de la méthode sendRequest().
  2. Supprimez le code interne de la branche try de la méthode onSuccess(). Ne supprimez pas la branche catch, car elle fait simplement appel à un gestionnaire d'erreur.
  3. Gardez l’implémentation de remplacement onError(), elle est suffisamment générique pour fonctionner avec n’importe quelle réponse Salesforce.

Voici l’appel à RestClient.sendAsync().

restRequest = RestRequest.getRequestForDelete(
        getString(R.string.api_version), "Contact",
        records.getJSONObject(position).getString("Id"));
client.sendAsync(restRequest, new AsyncRequestCallback() {
    @Override
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly();
        runOnUiThread(new Runnable() { 
            @Override
            public void run() {
                // Network component doesn’t report app layer status.
                // Use Mobile SDK RestResponse.isSuccess() method to check
                // whether the REST request itself succeeded.
                if (result.isSuccess()) {
                    try {

                    } catch (Exception e) {
                        onError(e);
                    }
                }
            }
        });
    }

    @Override
    public void onError(final Exception exception) {
        runOnUiThread(new Runnable() {
        @Override
            public void run() {
                Toast.makeText(MainActivity.this,
                        MainActivity.this.getString(R.string.sf__generic_error, exception.toString()),
                        Toast.LENGTH_LONG).show();
            }
        });
    }
});

Implémentation de la méthode de rappel onSuccess()

Dans la méthode onSuccess() de AsyncRequestCallback(), vous effectuez les opérations suivantes :
  1. Assurez-vous que l’opération de suppression a réussi en testant le statut HTTP. Cette vérification est nécessaire, car le composant de communauté sous-jacent renvoie uniquement les échecs de la couche de transport, pas les échecs de requêtes REST.
  2. Si l’opération réussit, retirez l’élément à la position indiquée de la vue de liste.
  3. Vous publiez un message de réussite.
Vous utilisez la variable de classe listAdapter pour supprimer la ligne. Vous pouvez appeler ArrayAdapter.remove(T object), à l'aide de la valeur de position transmise à la méthode onItemLongClick(), pour obtenir l'objet. Par exemple :
listAdapter.remove(listAdapter.getItem(position));
Si vous ajoutez ce code, vous rencontrerez un problème d'étendue. Comme vous travaillez dans un contexte d'implémentation d'interface, vous ne pouvez pas utiliser la variable locale position du contexte onItemLongClick(). Vous pouvez ajouter à la place une variable de classe et lui assigner la variable de position.
  1. En haut de la classe, déclarez et initialisez une variable de classe privée intitulée pos de type int.
    public class MainActivity extends SalesforceActivity {
    
        private RestClient client;
        private ArrayAdapter<String> listAdapter;
        private JSONArray records;
        private int pos = -1;
  2. Sur la première ligne de la méthode onItemLongClick(), capturez la valeur position :
    public boolean onItemLongClick(AdapterView<?> parent, View view,
    	int position, long id) {
    	pos = position;
    	...
  3. Dans la méthode onSuccess() de votre implémentation AsyncRequestCallback, faites défiler quelques lignes jusqu’au bloc if.
    if (result.isSuccess()) {
        try {
    
        } catch (Exception e) {
            onError(e);
        }
    }
  4. Si result.isSuccess() est true, retirez la ligne en appelant la méthode listAdapter.remove(). Utilisez pos au lieu de position pour retirer la ligne :
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
    
    }
  5. Après avoir supprimé un élément de la liste, appelez sendRequest(request) pour actualiser la liste réorganisée et la synchroniser avec votre tableau local records.
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
        sendRequest(”SELECT Name, Id FROM Contact”);
    
    }
  6. Pour terminer, publiez une case alerte qui présente un message de réussite. Sinon, indiquez le message d'erreur.
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
        sendRequest(”SELECT Name, Id FROM Contact”);
        AlertDialog.Builder b = new AlertDialog.Builder(findViewById(R.id.contacts_list).getContext());
        b.setMessage("Record successfully deleted!");
        b.setCancelable(true);
        AlertDialog a = b.create();
        a.show();
    } else {
       Toast.makeText(MainActivity.this,
             MainActivity.this.getString(R.string.sf__generic_error, result.toString()),
             Toast.LENGTH_LONG).show();
    }

Voici la méthode onItemLongClick() terminée.

@Override
public boolean onItemLongClick(AdapterView<?> parent, 
        View view, int position, long id) {
    pos = position;

    Toast.makeText(getApplicationContext(),
        "Long press detected", Toast.LENGTH_SHORT).show();
    RestRequest restRequest = null;
    try {
       RestRequest request = RestRequest.getRequestForDelete(
           getString(R.string.api_version), "Contact", 
               records.getJSONObject(position).getString("Id"));
       client.sendAsync(request, new AsyncRequestCallback() {
            @Override
            public void onSuccess(RestRequest request, final RestResponse result) {
                result.consumeQuietly();
                runOnUiThread(new Runnable() { 
                    @Override
                    public void run() {
                        try {
                            // Network component doesn’t report app layer status.
                            // Use Mobile SDK RestResponse.isSuccess() method to check
                            // whether the REST request itself succeeded. 
                            if (result.isSuccess()) {                                        
                                listAdapter.remove(listAdapter.getItem(pos));
                                sendRequest(”SELECT Name, Id FROM Contact”);
                                AlertDialog.Builder b = 
                                    new AlertDialog.Builder(findViewById
                                        (R.id.contacts_list).getContext());
                                b.setMessage("Record successfully deleted!");
                                b.setCancelable(true);
                                AlertDialog a = b.create();
                                a.show();
                            } else {
                                Toast.makeText(MainActivity.this,
                                    MainActivity.this.getString(
                                        R.string.sf__generic_error, 
                                        result.toString()),
                                    Toast.LENGTH_LONG).show(); 
                            }   
                        } catch (Exception e) {
                            onError(e);
                        }
                    }});
                }

                @Override
                public void onError(final Exception exception) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {		          
                            Toast.makeText(MainActivity.this,
                                MainActivity.this.getString(
                                    R.string.sf__generic_error, 
                                    exception.toString()),
                                Toast.LENGTH_LONG).show();
                        }
                    });
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    return true;
}

Mise à jour finale et exécution !

Le bouton Extraire les comptes est supprimé lors d'un léger nettoyage final. L'affichage de la liste étant partagé entre Extraire les contacts et Extraire les comptes, votre gestionnaire de pression longue s'applique également aux deux. Cependant, ce gestionnaire est inutile pour les comptes, car l'ID que vous utilisez pour supprimer l'enregistrement s'applique uniquement à un contact. En tant que « crédit supplémentaire », vous pouvez également appliquer ce que vous avez appris et adapter le gestionnaire de pression longue pour supprimer à la fois les contacts et les comptes. Cependant, pour ce didacticiel, supprimons le code associé aux comptes.

Supprimez les éléments suivants des fichiers indiqués :

Fichier Action
MainActivity.java Supprimez la méthode onFetchAccountsClick(View v).
res/layout/Main.xml Effectuez l’une des actions suivantes :
  • Dans Présentation graphique, supprimez le bouton « Extraire les comptes ».
  • Dans l’affichage XML, supprimez le nœud <Button> dont l’ID est « @+id/extraire_comptes ».
res/values/strings.xml Effectuez l’une des actions suivantes :
  • Dans l'onglet Ressources : Sélectionnez « bouton_extraire_comptes (Chaîne) » et cliquez sur Supprimer.
  • Dans l'affichage XML : Supprimez le nœud <string> qui s’intitule « fetch_accounts_button ».

Enfin, votre application est terminée et prête à fonctionner !

  1. Dans Android Studio, cliquez sur Run | Run ‘app’.
  2. Sélectionnez un appareil connecté ou un émulateur compatible avec le kit de développement Mobile SDK.
  3. Lorsque l’application est exécutée, connectez-vous à votre organisation Salesforce, puis cliquez sur Fetch Contacts pour afficher la liste. Touchez et maintenez un élément de la liste jusqu'à ce que vous voyiez un message toast qui confirme la pression longue.

Notez que vous recevez une réponse d’erreur lorsque vous essayez de supprimer un contact par défaut dans la base de données Developer Edition. Ces erreurs se produisent car chaque contact pré-empaqueté dans une organisation Developer Edition est le parent d’autres enregistrements. Pour préparer le test, connectez-vous à votre organisation Developer Edition, puis créez un ou plusieurs contacts test qui n’ont pas d’autres enregistrements. Si la suppression est réussie, un message apparaît indiquant que l'enregistrement a été supprimé.

Partagez vos commentaires sur Trailhead dans l'aide Salesforce.

Nous aimerions connaître votre expérience avec Trailhead. Vous pouvez désormais accéder au nouveau formulaire de commentaires à tout moment depuis le site d'aide Salesforce.

En savoir plus Continuer à partager vos commentaires