function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Martin S.Martin S. 

Illegal assignment from Case to String

Hello,
I am trying to get the recordId in another component. Therefore I wrote a extra Apex method but I am not sure how to get the recordId there. 

Here I need to have the recordId of a Contact to get the right data
/**
   * Returns a case by its ID
   *
   * @param      id    The identifier
   *
   * @return     The case.
   */
  @AuraEnabled
  public static Case getCaseWithContact(Id id) {
    return [
      SELECT
        Id,
        Contact.Name,
        Contact.LastName,
        Contact.FirstName,
        Contact.MailingStreet,
        Contact.MailingCountry,
        Contact.Country_ISO_3166_2__c,
        Contact.MailingPostalCode,
        Contact.MailingCity,
        Contact.Phone,
        Contact.MobilePhone,
        Contact.Fax,
        Contact.Email,
        Contact.CustomerNumberNav__c,
        Contact.CustomerNumberSF__c,
        Contact.SalutationNavisionExport__c
        FROM Case WHERE Id = :id

    ];
  }

I tryed to create a method that gets the recordId and then give it to the getCaseWithContact like:
 
@AuraEnabled
  public static String getIdFromContactInCaseString(Id id) {

    List <case> ownerIdRec = [SELECT VehicleOwner__c FROM Case WHERE Id = :id];

    String ownerIdRecord = ownerIdRec[0];

    return ownerIdRecord;

  }

But there I get the Error Illegal assignment from Case to String.

Can someone help me or give me a tipp?
 
Best Answer chosen by Martin S.
Paul S.Paul S.
Martin,

You're getting that error because ownerIdRec[0] is a Case, not a String.  You'd want to use something like the following, depending on which Id you're actually looking for (I think the latter).
String ownerIdRecord = ownerIdRec[0].Id;

-or-

String ownerIdRecord = ownerIdRec[0].VehicleOwner__c;

All Answers

Paul S.Paul S.
Martin,

You're getting that error because ownerIdRec[0] is a Case, not a String.  You'd want to use something like the following, depending on which Id you're actually looking for (I think the latter).
String ownerIdRecord = ownerIdRec[0].Id;

-or-

String ownerIdRecord = ownerIdRec[0].VehicleOwner__c;
This was selected as the best answer
Martin S.Martin S.
Thank you very much Paul! With that I dont get errors.
But I thought wrong, we have a object with 2 related records (a account and a contact) and the method get the recordId from the account related record. So I need a possibility to get the recordId from the contact related record.

We have a switch (in the Helper.js) witch select the right method for the sql statement. The 'getContactInCase' method is from me and it makes the same like 'getCaseWithContact' witch select some data by recordId.
switch (context) {
      case 'Case' : task = 'getCase';
            break;
      case 'CaseWithContact' : task = 'getCaseWithContact';
            break;
      case 'PersonAccount' : task = 'getAccount';
            break;
      case 'Contact' : task = 'getContact';
            break;
      case 'ContactInCase' : task = 'getContactInCase';
            break;
        default: task = 'getCase';
    }

    // request data from 'task'
          DataService.exec(
			task, 
			component, 
      		{
        		id: component.get('v.recordId')
      		}
    	 )
Do you know how I can get here a recordId from a related record? The main object where I am in is 'case' and it has a Lookup to Contact with the recordId in VehicleOwner__c.
Can I access in js to that or was java right?
Thanks in advance!
Paul S.Paul S.
Hi Martin - I'm not sure I'm 100% following you here.  You stated "we have a object with 2 related records..."  What is that record?  A case?  Some other record/object?
Martin S.Martin S.
Hi Paul - Sorry for that.
We have a object "case" where when a customer calls all his information can be displayed. There we have a related record which points to a account (business contact / dealer) and a related record which points to a contact (to the consumer). 
The actuall logic takes the recordId from the dealer account and get some infos for creating a link to another system.
I want to take the recordId from the consumer contact and create a link with that Id. 

In the apex class there is already a method that get all contact informations and create that link so I need only to give from the helper.js the right recordId to apex and that should work I hope.

My first try was to make an sql statement in apex that get me the recordId like SELECT Contact.VehicleOwner__c FROM case WHERE Id = :CaseRecordId but that was not working and because the case object has a lookup field VehicleOwner__c to contact I thought it would be easier to get the Id direct in the Helper.js

Can't I make something like 
 
// request data from 'task'
          DataService.exec(
            task,
            component,
            {
                id: component.get('Contact.VehicleOwner__c')
            }
         )


// Instead of

// request data from 'task'
          DataService.exec(
            task,
            component,
            {
                id: component.get('v.recordId')
            }
         )

Thanks for your time :)
Paul S.Paul S.
Hi Martin - can you please post what you have so far and I can take a look?  I'm having a tough time seeing the big picture.  If you'd rather not post that here, let me know and we can find some other method.  Thanks.
Martin S.Martin S.
Hi, I can post it here. 

//NavisionNavigator.cmp
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId" controller="NavisionNavigatorController">
      
<!-- app scripts -->
<ltng:require scripts="{!join(',', $Resource.AuraServiceHelper + '/DataService.js', $Resource.AuraServiceHelper + '/EventHelper.js', $Resource.AuraServiceHelper + '/Locale.js')}"
  afterScriptsLoaded="{!c.initResources}"
/>

<!-- Handler -->
<aura:handler name="init" value="{!this}" action="{!c.init}"/>
<aura:handler event="force:refreshView" action="{!c.handleRecordUpdated}"/>


<!-- Attributes -->
<aura:attribute name="data" type="Object"/>
<aura:attribute name="disableMap" type="Object"/>
<aura:attribute name="context" type="String"/>

<!-- Markup -->
<article class="slds-card">
  <div class="slds-card__header slds-grid">
    <header class="slds-media slds-media_center slds-has-flexi-truncate">
      <div class="slds-media__figure">
        <lightning:icon iconName="standard:poll" size="small"/>
      </div>
      <div class="slds-media__body">
        <h2>
          <a href="javascript:void(0);" class="slds-card__header-link slds-truncate">
            <span class="slds-text-heading_small">Navision Cockpit</span>
          </a>
        </h2>
      </div>
    </header>
    <div class="slds-no-flex">
      <button class="slds-button slds-button_neutral" onclick="{!c.init}">
        <lightning:icon iconName="utility:refresh" size="x-small"/>
      </button>
    </div>
  </div>
  <div class="slds-card__body slds-card__body_inner">
    <div class="slds-grid">
      <div class="slds-col slds-size_1-of-6"></div>
      <div class="slds-col slds-size_4-of-6">
        <aura:if isTrue="{!equals(v.context,'Case')}">
          <p>
            <lightning:button variant="brand"
              iconName="utility:user"
              iconPosition="left"
              name="show"
              label="Account in Navision anzeigen"
              onclick="{!c.handleClick}"
              disabled="{!v.disableMap.show}"
            />
          </p>
          <p>
            <lightning:button variant="brand"
              iconName="utility:adduser"
              iconPosition="left"
              name="newUser"
              label="Account anlegen / aktualisieren" 
              onclick="{!c.handleClick}" 
              disabled="{!v.disableMap.newUser}"
            />
          </p>
        </aura:if>
        <aura:if isTrue="{!equals(v.context,'CaseWithContact')}">
          <p>
            <lightning:button variant="brand"
              iconName="utility:user"
              iconPosition="left"
              name="showCaseWithContact"
              label="Kontakt in Navision anzeigen"
              onclick="{!c.handleClick}"
              disabled="{!v.disableMap.showCaseWithContact}"
            />
          </p>
          <p>
            <lightning:button variant="brand"
              iconName="utility:adduser"
              iconPosition="left"
              name="newUserCaseWithContact"
              label="Kontakt anlegen / aktualisieren" 
              onclick="{!c.handleClick}" 
              disabled="{!v.disableMap.newUserCaseWithContact}"
            />
          </p>
        </aura:if>
        <aura:if isTrue="{!equals(v.context,'PersonAccount')}">
          <aura:if isTrue="{!v.data.IsPersonAccount}">
            <p>
              <lightning:button variant="brand"
                iconName="utility:user"
                iconPosition="left"
                name="showPersonAccount"
                label="Account in Navision anzeigen"
                onclick="{!c.handleClick}"
                disabled="{!v.disableMap.showPersonAccount}"
              />
            </p>
            <p>
              <lightning:button variant="brand"
                iconName="utility:adduser"
                iconPosition="left"
                name="addPersonAccount"
                label="Account anlegen / aktualisieren" 
                onclick="{!c.handleClick}" 
                disabled="{!v.disableMap.addPersonAccount}"
              />
            </p>
            <aura:set attribute="else">
              <p>Kein Person Account!</p>
            </aura:set>

          </aura:if>
        </aura:if>
        <aura:if isTrue="{!equals(v.context,'Contact')}">
          <aura:if isTrue="{!v.data.IsCustomer__c}">
            <p>
              <lightning:button variant="brand"
                iconName="utility:user"
                iconPosition="left"
                name="showContact"
                label="Kontakt in Navision anzeigen"
                onclick="{!c.handleClick}"
                disabled="{!v.disableMap.showContact}"
              />
            </p>
            <p>
              <lightning:button variant="brand"
                iconName="utility:adduser"
                iconPosition="left"
                name="addContact"
                label="Kontakt anlegen / aktualisieren" 
                onclick="{!c.handleClick}" 
                disabled="{!v.disableMap.addContact}"
              />
            </p>
            <aura:set attribute="else">
              <p>Kein Privatkunde!</p>
            </aura:set>
          </aura:if>
        </aura:if>
      </div>
      <div class="slds-col slds-size_1-of-6"></div>
    </div>
    
  </div>
  <footer class="slds-card__footer"></footer>
</article>
  


</aura:component>


NavisionNavigatorController.js
({
	
  init: function(component, event, helper){
    if (helper.resourcesLoaded()) {
      helper.getInitData(component);
    }
  },

  initResources: function(component, event, helper) {
    if (!helper.resourcesLoaded()) {
      helper.setResourcesLoaded();
      helper.getInitData(component);
    }
  },

  handleClick: function(component, event, helper) {
    helper.navigateTo(component, event.target.name);
  },

  handleRecordUpdated: function(component, event, helper) {
    if (helper.resourcesLoaded()) {
      helper.getInitData(component);
    }
  }

})


NavisionNavigatorHelper.js
({
  /**
   * Contains the main redirector url.
   */
   REDIRECTOR: "http://sfredirect.servpool.local/sfredirect.html##",
  /**
   * Contains all URLS for every button.
   * Every URL contains <Name> like placeholders which are replaced during processing.
   */
	URL: {
    show: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'ShowNavCases'|'<Contact.Account.PersonEmail>'|'<Contact.Account.Phone>'|''|''|'<Contact.Account.CustomerNumberNav__c>'|'<Contact.CustomerNumberSF__c>'|''))",
    newUser: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'upsertContact'|'<Contact.CustomerNumberSF__c>'|'<Contact.LastName>'|'<Contact.FirstName>'|'<Contact.Account.BillingStreet>'|''|'<Contact.Account.Country_ISO_3166_2__c>-<Contact.Account.BillingPostalCode>'|'<Contact.Account.BillingCity>'|'<Contact.Phone>'|'<Contact.Account.PersonMobilePhone>'|'<Contact.Account.Fax>'|'<Contact.Account.PersonEmail>'|''|''|''|''|'<Contact.SalutationNavisionExport__c>'|'<Contact.Account.CustomerNumberNav__c>'))",
    showCaseWithContact: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'ShowNavCases'|'<Contact.Email>'|'<Contact.Phone>'|''|''|'<Contact.CustomerNumberNav__c>'|'<Contact.CustomerNumberSF__c>'|''))",
    newUserCaseWithContact: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'upsertContact'|'<Contact.CustomerNumberSF__c>'|'<Contact.LastName>'|'<Contact.FirstName>'|'<Contact.MailingStreet>'|''|'<Contact.Country_ISO_3166_2__c>-<Contact.MailingPostalCode>'|'<Contact.MailingCity>'|'<Contact.Phone>'|'<Contact.MobilePhone>'|'<Contact.Fax>'|'<Contact.Email>'|''|''|''|''|'<Contact.SalutationNavisionExport__c>'|'<Contact.CustomerNumberNav__c>'))",
    showPersonAccount: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'ShowNavCases'|'<PersonEmail>'|'<Phone>'|''|''|'<CustomerNumberNav__c>'|'<PersonContact.CustomerNumberSF__c>'|''))",
    addPersonAccount: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'upsertContact'|'<PersonContact.CustomerNumberSF__c>'|'<PersonContact.LastName>'|'<PersonContact.FirstName>'|'<BillingStreet>'|''|'<Country_ISO_3166_2__c>-<BillingPostalCode>'|'<BillingCity>'|'<Phone>'|'<PersonMobilePhone>'|'<Fax>'|'<PersonEmail>'|''|''|''|''|'<SalutationNavisionExport__pc>'|'<CustomerNumberNav__c>'))",
    showContact: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'ShowNavCases'|'<Email>'|'<Phone>'|''|''|'<CustomerNumberNav__c>'|'<CustomerNumberSF__c>'|''))",
    addContact: "navision://client/run?target=Form 50238&activ=true&view=SORTING(FIELD1,FIELD2,FIELD3)WHERE(FIELD6=FILTER(*|'upsertContact'|'<CustomerNumberSF__c>'|'<LastName>'|'<FirstName>'|'<MailingStreet>'|''|'<Country_ISO_3166_2__c>-<MailingPostalCode>'|'<MailingCity>'|'<Phone>'|'<MobilePhone>'|'<Fax>'|'<Email>'|''|''|''|''|'<SalutationNavisionExport__c>'|'<CustomerNumberNav__c>'))"
  },

  /**
   * Global indicator to marks static resources as loaded.
   */
  resourcesLoadedState: false,

  /**
   * Dependency map.
   * Holds the required fields for every button.
   * Every field needs to have a value. If not, buttons is disabled.
   */
  dependencyMap: {
    show: ['Account.CustomerNumberNav__c'],
    newUser: ['Contact', 'Account'],
    showCaseWithContact: ['Contact.CustomerNumberNav__c'],
    newUserCaseWithContact: ['Contact'],
    showPersonAccount : ['CustomerNumberNav__c'],
    addPersonAccount: ['PersonContact.LastName','PersonContact.FirstName'],
    showContact : ['CustomerNumberNav__c'],
    addContact: ['LastName','FirstName']
  },

  /**
   * Opens a new window.
   * The window's URL is created with the template.
   * Every placeholder is replaced by a value or an empty string.
   *
   * @param      {Object}  component  The component
   * @param      {String}  action     The action value
   */
  navigateTo: function(component, action) {
    // check, if the action exists. If not, stop here.
    if (!this.URL[action]) {
      return;
    }

    // open a new window without statusbar, menubar and locationbar, 400x400 px dimension
    window.open(
      this.REDIRECTOR + encodeURIComponent(this.replacer(this.URL[action], component.get('v.data'))),
      'window',
      'height=400, width=400, status=no, menubar=no, location=no'
    );
    
  },

  /**
   * Replaces all Placeholders
   *
   * @param      {string}  url     The url
   * @param      {<type>}  data    The data
   * @return     {string}  { description_of_the_return_value }
   */
  replacer: function(url, data) {
    // no data, empty window
    if (!data) {
      return 'about:blank';
    }

    var _this = this;

    // regex to find placeholders
    var regexReplacer = /(<[\w\.]+>)/g,
        regexFields = /<([\w\.]+)>/g
    ;

    // placeholder matches
    var matchesReplacer = url.match(regexReplacer),
        matchesFields   = url.match(regexFields)
    ;

    // pointer on the current replaced item
    var replaceItem = null;

    // remove all < > from findings and split on every .
    matchesFields = matchesFields.map(function(item) { return item.replace(/[<>]/g, '').split('.')});

    // replace every placeholder with value
    matchesReplacer.forEach(function(entry, index) {
      replaceItem = matchesFields[index];
      console.log(replaceItem, data[replaceItem[0]] );
      url = url.replace(
        entry, 
        // replaceItem.length > 1 ? 
        //   (
        //     data[replaceItem[0]] ? 
        //     (
        //       data[replaceItem[0]][replaceItem[1]] || ''
        //     ) 
        //     : ''
        //   ) 
        // : (data[replaceItem[0]] || '')
        _this.pathDataResolver(replaceItem, data)
      );
    });
    
    return url;
  },

  pathDataResolver: function(path, data) {
    return path.reduce(
      function(result, value) { return result ? result[value] : undefined; }
      ,
      data
    ) || '';
  },

  /**
   * Requests case data from salesforce
   *
   * @param      {Object}  component  The component
   */
  getInitData: function(component) {
    // pointer to this context
    var _this = this;

    // get the context
    var context = component.get('v.context');
    var task;

    switch (context) {
      case 'Case' : task = 'getCase';
            break;
      case 'CaseWithContact' : task = 'getCaseWithContact';
            break;
      case 'PersonAccount' : task = 'getAccount';
            break;
      case 'Contact' : task = 'getContact';
            break;
      case 'ContactInCase' : task = 'getContactInCase';
            break;
        default: task = 'getCase';
    }

    // request data from 'task'
          DataService.exec(
			task, 
			component, 
      		{
        		id: component.get('v.recordId')
      		}
    	 )
    .then(function(data) {
      // set data
      component.set('v.data', data);
      console.log(data);

      _this.resolveButtonDependencies(component, data);
    });
  },

  /**
   * Decides which buttons need to be disabled.
   * Uses @var dependencyMap to generate status.
   *
   * @param      {Object}  component  The component
   * @param      {Object}  data       The case data
   */
  resolveButtonDependencies: function(component, data) {

    // pointer to this
    // locker object that contains every locked object
    var _this = this,
        locker = {}
    ;

    // iterate through every dependency entry
    Object.keys(this.dependencyMap).forEach(function(key) {

      var item = _this.dependencyMap[key],
          lockItem = false
      ;

      // walk through every depending object for this field
      item.forEach(function(dependency) {
        // split the string at every .
        var fields = dependency.split('.'),
            walker = data;

        // walk through every splitted part and check if the field exists
        // If not, lock the item
        fields.forEach(function(field) {
          if (walker[field]) {
            walker = walker[field];
          } else {
            lockItem = true;
          }
        });

        if (lockItem) {
          locker[key] = true;
        }
      });
    });
    component.set('v.disableMap', locker);
  },

  /**
   * Returns if all resources have been loaded
   *
   * @return     {Boolean}
   */
  resourcesLoaded: function() {
    return this.resourcesLoadedState;
  },

  /**
   * Marks resources as loaded.
   */
  setResourcesLoaded: function() {
    this.resourcesLoadedState = true;
  }
})


The NavisionNavigator.design with the context cases
<design:component >
  <design:attribute name="context" datasource="Case,CaseWithContact,PersonAccount,Contact,ContactInCase" label="Context" default="Case"/>
</design:component>
Martin S.Martin S.
The NavisionNavigatorController.java -apex class
**
 * Navision Navigation controller
 */
public with sharing class NavisionNavigatorController {
  /**
   * Returns a case by its ID
   *
   * @param      id    The identifier
   *
   * @return     The case.
   */
  @AuraEnabled
  public static Case getCase(Id id) {
    return [
      SELECT
        Id,
        Account.LastName,
        Account.FirstName,
        Contact.Account.BillingStreet,
        Contact.Account.BillingCountry,
        Contact.Account.BillingCity,
        Contact.Phone,
        Contact.Account.PersonMobilePhone,
        Contact.Account.Fax,
        Contact.Account.PersonEmail,
        Contact.Account.BillingPostalCode,
        Contact.Account.CustomerNumberNav__c,
        Contact.Account.CustomerNumberSF__c,
        Contact.Account.Country_ISO_3166_2__c,
        Contact.Name,
        Contact.CustomerNumberSF__c,
        Contact.FirstName,
        Contact.LastName,
        Contact.SalutationNavisionExport__c
        FROM Case WHERE Id = :id
      
    ];
  }

  /**
   * Returns a case by its ID
   *
   * @param      id    The identifier
   *
   * @return     The case.
   */
  @AuraEnabled
  public static Case getCaseWithContact(Id id) {
    return [
      SELECT
        Id,
        Contact.Name,
        Contact.LastName,
        Contact.FirstName,
        Contact.MailingStreet,
        Contact.MailingCountry,
        Contact.Country_ISO_3166_2__c,
        Contact.MailingPostalCode,
        Contact.MailingCity,
        Contact.Phone,
        Contact.MobilePhone,
        Contact.Fax,
        Contact.Email,
        Contact.CustomerNumberNav__c,
        Contact.CustomerNumberSF__c,
        Contact.SalutationNavisionExport__c
        FROM Case WHERE Id = :id
      
    ];
  }

  /**
   * Returns an account by it's id.
   *
   * @param      id    The identifier
   *
   * @return     The account.
   */
  @AuraEnabled
  public static Account getAccount(Id id) {
    return [
      SELECT
        Id,
        Phone,
        PersonMobilePhone,
        PersonEmail,
        CustomerNumberNav__c,
        PersonContact.CustomerNumberSF__c,
        PersonContact.LastName,
        PersonContact.FirstName,
        BillingStreet,
        Country_ISO_3166_2__c,
        BillingPostalCode,
        BillingCity,
        Fax,
        SalutationNavisionExport__pc,
        IsPersonAccount
        
        FROM Account WHERE Id = :id

      
    ];
  }
  /**
   * Returns an contact by it's id.
   *
   * @param      id    The identifier
   *
   * @return     The contact.
   */
  @AuraEnabled
  public static Contact getContact(Id id) {
    return [
      SELECT
        Id,
        FirstName,
        LastName,
        Salutation,
        Phone,
        MobilePhone,
        Fax,
        Email,
        CustomerNumberNav__c,
        CustomerNumberSF__c,
        MailingStreet,
        MailingPostalCode,
        MailingCity,
        Country_ISO_3166_2__c,
        SalutationNavisionExport__c,
        IsCustomer__c
        
        FROM Contact WHERE Id = :id

      
    ];
  }
    /**
   * Returns an VehicleOwner by it's id.
   *
   * @param      id    The identifier
   *
   * @return     The contact.
   */
  @AuraEnabled
  public static String getIdFromContactInCaseString(Id id) {

    List <case> ownerIdRec = [SELECT VehicleOwner__c FROM Case WHERE Id = :id];
    String ownerIdRecord = ownerIdRec[0].VehicleOwner__c;
    return ownerIdRecord;

  }


/**
   * Returns a case by its ID
   *
   * @param      id    The identifier
   *
   * @return     The case.
   */
  @AuraEnabled
  public static Case getIdFromContactInCase(Id id) {
    String recId = getIdFromContactInCaseString(id);
    return [
      SELECT
        Id,
        Contact.Name,
        Contact.LastName,
        Contact.FirstName,
        Contact.MailingStreet,
        Contact.MailingCountry,
        Contact.Country_ISO_3166_2__c,
        Contact.MailingPostalCode,
        Contact.MailingCity,
        Contact.Phone,
        Contact.MobilePhone,
        Contact.Fax,
        Contact.Email,
        Contact.CustomerNumberNav__c,
        Contact.CustomerNumberSF__c,
        Contact.SalutationNavisionExport__c
        FROM Case WHERE Id = :recId

    ];
  }
}


And the DataService that creates the choosen function
(function() {
    /**
	 * Generates a Service that allows dynamical execution of controller methods.
	 * Exports function 'exec' to execute method in controller.
	 *
	 * This service can be used in every Lightning component.
	 *
	 * Usage:
	 *
	 * Module exports global DataService class in window object.
	 * Within LockerService every component has its own DataService class.
	 *
	 * To call a controller action execute:
	 *
	 * <pre>
	 *
	 * DataService.exec('actionName', component, params);
	 *
	 * </pre>
	 *
	 * This will call the controller action.
	 *
	 * Method signature of exec:
	 *
	 * DataService.exec(String actionName, component [, Object params])
	 *
	 * params must be a key/value object.
	 *
	 * component is the component object that was passed into javascript controller method.
	 *
	 * exec() uses native browser Promise implementation.
	 * In IE Lightning/Aura will use an own promise library that works similiar to native promises.
	 *
	 * To get the data that was returned by controller action, use the promise then():
	 *
	 * <pre>
	 *
	 * DataService
	 * 		.exec('someFunctionThatReturnsData', component, {someParamsWithValues : 123})
	 * 		.then(function(data){
	 * 			// data contains returned data
	 * 		})
	 * ;
	 *
	 * </pre>
	 *
	 * To catch request/response errors, append catch() to promise chain:
	 *
	 * <pre>
	 *
	 * DataService
	 * 		.exec('someFunctionThatReturnsData', component, {someParamsWithValues : 123})
	 * 		.then(function(data){
	 * 			// data contains returned data
	 * 		})
	 * 		.catch(function(errors){
	 * 			// errors is an array with one message per array entry
	 * 		})
	 * ;
	 *
	 * </pre>
	 *
	 *
	 * @version    (1.0.1)
	 * @class      Service ()
	 * @return     {Object}  { Exported function 'exec' }
	 */
    function Service() {

        /**
		 * Contains functions created by the the function factory.
		 * Provides reusing of functions.
		 *
		 * @type       {Object}
		 */
        var functions = {};

        /**
		 * Factory that generates reusable functions
		 * that perform calls to controller methods.
		 *
		 * Every function uses promises so devs can use then() statements in their call.
		 *
		 * @class      FunctionFactory (name)
		 * @param      {String}  functionName  Controller method name that should be executed.
		 * @return     {Function}  { The generated function that's being executed every time the user calls Service.exec(functionName) }
		 */
        var FunctionFactory = function(functionName) {
            /**
			 * Self execution function that returns new function with it's own scope.
			 *
			 * @param      {string}    name    Function name
			 * @return     {Function}  { Function that has the data as argument }
			 */
            var fn = (function(name) {

                /**
				 * Returns new function that receives data object and isolates in own scope
				 */
                return function(component, data) {

                    // returns Callback function from Aura framework
                    // Callback set by action.setCallback();
                    // This resolves/rejects promise
                    return $A.getCallback(function() {
                        /**
						 * Promise that handles request result
						 *
						 * @type       {Promise}
						 */
                        var promise = new Promise($A.getCallback(function(resolve, reject) {

                            function errorHandler(errors) {

                                var messages = [];

                                function getMessages(errorType) {

                                    var tempMessages = [];

                                    if (errorType.length) {

                                        errorType.forEach(function(errorEntry) {
                                            tempMessages.push(errorEntry.message);
                                        });

                                    } else {

                                        for (var prop in errorType) {
                                            errorType[prop].forEach(function(errorEntry) {
                                                tempMessages.push(errorEntry.message);
                                            });
                                        }

                                    }
                                    return tempMessages;

                                }

                                for (var err in errors) {

                                    if (errors[err].duplicateResults && errors[err].duplicateResults.length > 0) {
                                        messages = messages.concat(getMessages(errors[err].duplicateResults));
                                    }

                                    if (errors[err].pageErrors && errors[err].pageErrors.length > 0) {
                                        messages = messages.concat(getMessages(errors[err].pageErrors));
                                    }

                                    if (errors[err].fieldErrors && errors[err].fieldErrors.length > 0) {
                                        messages = messages.concat(getMessages(errors[err].fieldErrors));
                                    }

                                    if (errors[err].index && errors[err].index.length > 0) {
                                        messages = messages.concat(getMessages(errors[err].index));
                                    }
                                }
                                return messages;
                            }

                            /**
							 * Object that contains Action Class from Aura framework
							 * to connect to controller function.
							 *
							 * @type       {Object}
							 */
                            var action;

                            // try to generate action object for given method name
                            // fails, if method does not exist in component controller
                            try {
                                action = component.get('c.' + name);
                            } catch (exception) {
                                // reject promise so user can handle error
                                reject([exception.message]);
                                return;
                            }

                            // if call contains data for request, set it
                            if (data) {
                                action.setParams(data);
                            }

                            // set the callback function thats being executed after response from server arrived
                            // this part resolves/rejects promise with error message or response data.
                            action.setCallback(false, function(returnObject) {

                                // switch state code and decide to resolve or reject promise
                                switch (returnObject.getState()) {
                                    // success case => resolves promise with returned data
                                case 'SUCCESS':
                                    resolve(returnObject.getReturnValue());
                                    break;

                                    // ERROR (deprecated) or FAILURE cases will reject with error message(s)
                                case 'ERROR':
                                case 'FAILURE':
                                    reject(errorHandler(returnObject.getError()));
                                    break;

                                    // INCOMPLETE will reject with incomplete message
                                case 'INCOMPLETE':
                                    reject(['Incomplete response from server!']);
                                    break;

                                    // every other state will reject with unknown status code message
                                default:
                                    reject(['Unknown status code!']);
                                    break;
                                }

                            });

                            // execute action
                            $A.enqueueAction(action, false);

                        }));

                        // return the promise
                        return promise;
                    })

                }
            }
            )(functionName);

            // return the generated function
            return fn;
        }

        /**
		 * Executes function and calls method in controller via Aura framework.
		 *
		 * Dynamically generates reusable functions.
		 *
		 * @param      {String}  functionName  Name of function to be called
		 * @param      {Object}  data          Data to be sent to server
		 * @return     {Promise}  { Promise object so dev can get results via .then() }
		 */
        this.exec = function(functionName, component, data) {

            // check if function does not exists.
            // if not, call factory
            if (!functions[functionName]) {
                functions[functionName] = FunctionFactory(functionName);
            }

            // execute function and return its result
            return functions[functionName](component, data)();
        }
        ;

    }
    // generate global data access object
    window.DataAccess = window.DataService = new Service();
}
)();

Here is how it looks in the Case: 
In 1 the NavisionNavigator gets the recordId from the component and selects the data right. (Contact is here the Account of a dealer / reseller)
But in 2 it dont know how I can select there the recordId of the customer (who buys it from the reseller) from the "Halter"

Contact Details and Halter Details are both related records.

User-added image


And in "Edit Page" I can select the context which are set in the NavisionNavigator.design

In the Apex class the last 2 functions were my attempt to implement this

 
Paul S.Paul S.
Hi Martin - haven't forgotten about you.  Two quick questions.  First, what is setting the "context" variable?  Second, am I correct in my understanding that you're attempting to render a second Navision Cockpit component?

I think that part of the issue is that DataService is being passed the task/function that it should call (getCaseWithContact, for example) based on the "context," but there doesn't seem to be any way for it to know it should call the methods you've since created.  For example, you'd previously posted/asked:
// request data from 'task'
          DataService.exec(
            task,
            component,
            {
                id: component.get('Contact.VehicleOwner__c')
            }
         )


// Instead of

// request data from 'task'
          DataService.exec(
            task,
            component,
            {
                id: component.get('v.recordId')
            }
         )
The answer to that question is, well, yes and no.  The "context" of the page is going to ultimately determine what the "task" is.  If my assumption regarding my initial question is correct and "context" is being set because you're on a case page, you may just be passing Contact.VehicleOwner__c to the getCaseWithContact method.
Martin S.Martin S.
Hi Paul - I'm glad you help me at all so take your time.
The context is set by the Lightning App Builder (Pages) - when I am at a case and click on "Edit this Page" I can insert the custom component NavisionNavigator. There I can choose from the entered list from NavisionNavigator.design
<design:component >
  <design:attribute name="context" datasource="Case,CaseWithContact,PersonAccount,Contact,ContactInCase" label="Context" default="Case"/>
</design:component>
And yes there should be a second rendered component.


I would have solved it that way after your answer, or is it too cumbersome? : 
switch (context) {
  case 'Case':
    task = 'getCase';
    DataService.exec(
      task, 
      component, 
      {
        id: component.get('v.recordId')
      }
    )
    break;
  case 'CaseWithContact':
    task = 'getCaseWithContact';
    DataService.exec(
      task, 
      component, 
      {
        id: component.get('v.recordId')
      }
    )
    break;
  case 'PersonAccount':
    task = 'getAccount';
    DataService.exec(
      task, 
      component, 
      {
        id: component.get('v.recordId')
      }
    )
    break;
  case 'ContactInCase':
    task = 'getContactInCase';
    DataService.exec(
      task, 
      component, 
      {
        id: component.get('Contact.VehicleOwner__c')
      }
    )
    break;
}
.then(function(data) {
  // set data
  component.set('v.data', data);
  console.log(data);

  _this.resolveButtonDependencies(component, data);
});
},

 
Paul S.Paul S.
Hi Martin - if that works and it doesn't introduce any unintended side effects, it should be fine.  On the other hand, you may find that at a certain point you've added so many different contexts to the helper that it's become cumbersome and you want to refactor...but I don't think it's there yet.