0

A lightning component I created had three String attributes used to display/toggle the placeholder text in a ui:inputText: placeholder (the default placeholder), noResultsMessage (for when a query returned no results), and displayedPlaceholder (the actual ui:inputText placeholder) whose default value was {!v.placeholder}.

<aura:attribute name="placeholder" type="String" default="- Please Select an Option -" />
<aura:attribute name="noResultsMessage" type="String" default="- Query returned no results -" />
<aura:attribute name="displayedPlaceholder" type="String" default="{!v.placeholder}" />

<div>
    <ui:inputText  placeholder="{!v.displayedPlaceholder}" click="{!c.toggleDropdown}" change="{!c.searchSObjectList}" class="searchbarInput" value="{!v.searchbar.query}"/>
    <div aura:id="dropdown" class="slds-dropdown-trigger slds-dropdown-trigger_click searchbarInput searchbarDropdown slds-scrollable__x">
      <div class="slds-dropdown slds-dropdown_left slds-dropdown_length-7" style="width:20rem" onscroll="{!c.loadMoreResults}">
        <ul class="slds-dropdown__list" role="menu">
        <aura:iteration items="{!v.searchbar.displayList}" var="obj">
          <li class="slds-dropdown__item" role="presentation" > 
            <a href="javascript:void(0);" role="menuitem" tabindex="0">
              <span onclick="{!c.selectSObject}" title="{!obj.Name}" id="{!obj.salesforceId}">{!obj.searchableData}</span>
            </a>
          </li>
        </aura:iteration>
        </ul>
      </div>
    </div>
</div>

When a drop-down item was clicked, it made a server-side request for the results of a SOQL query based off of what SObject was clicked. A helper method, togglePlaceholder, was then called to toggle the placeholder based on whether or not the query had results.

togglePlaceholder : function(component, displayDefaultPlaceholder){
    var displayedPlaceholder = component.get('v.displayedPlaceholder');
    var placeholder = component.get('v.placeholder');
    var noResultsMessage = component.get('v.noResultsMessage');
    if(displayDefaultPlaceholder){      
        displayedPlaceholder = placeholder;         
    }
    else{           
        displayedPlaceholder = noResultsMessage;
    }
    component.set('v.displayedPlaceholder', displayedPlaceholder);
},

When you chose an option that returned no results, it would properly set the noResultsMessage, but it would then never switch back to the original placeholder. I added some console.logs and got the results below.

togglePlaceholder : function(component, displayDefaultPlaceholder){
    console.log('toggle placeholder ' + component.get('v.SObject'));
    console.log('before');
    console.log('placeholder: ' + component.get('v.placeholder'));
    console.log('no results:  ' + component.get('v.noResultsMessage'));
    console.log('displayed:   ' + component.get('v.displayedPlaceholder'));
    var displayedPlaceholder = component.get('v.displayedPlaceholder');
    var placeholder = component.get('v.placeholder');
    var noResultsMessage = component.get('v.noResultsMessage');
    if(displayDefaultPlaceholder){          
        console.log('SETTING ORIGINAL');
        displayedPlaceholder = placeholder;         
    }
    else{
        console.log('SETTING NO RESULTS');
        displayedPlaceholder = noResultsMessage;
    }
    component.set('v.displayedPlaceholder', displayedPlaceholder);
    console.log('after');
    console.log('placeholder: ' + component.get('v.placeholder'));
    console.log('no results:  ' + component.get('v.noResultsMessage'));
    console.log('displayed:   ' + component.get('v.displayedPlaceholder'));
},

toggle placeholder Patient__c

before

placeholder: - Please Select a Patient -

no results: - No Patients Fit Your Criteria -

displayed: - Please Select a Patient -

SETTING NO RESULTS

after

placeholder: - No Patients Fit Your Criteria -

no results: - No Patients Fit Your Criteria -

displayed: - No Patients Fit Your Criteria -

Note: the placeholder text is a bit different than what's set in the HTML because I was passing placeholders into the component based off SObject.

I then changed the helper method to explicitly reset placeholder and noResultsMessage, and got the results below:

togglePlaceholder : function(component, displayDefaultPlaceholder){
    console.log('toggle placeholder ' + component.get('v.SObject'));
    console.log('before');
    console.log('placeholder: ' + component.get('v.placeholder'));
    console.log('no results:  ' + component.get('v.noResultsMessage'));
    console.log('displayed:   ' + component.get('v.displayedPlaceholder'));
    var displayedPlaceholder = component.get('v.displayedPlaceholder');
    var placeholder = component.get('v.placeholder');
    var noResultsMessage = component.get('v.noResultsMessage');
    if(displayDefaultPlaceholder){          
        console.log('SETTING ORIGINAL');
        displayedPlaceholder = placeholder;         
    }
    else{
        console.log('SETTING NO RESULTS');
        displayedPlaceholder = noResultsMessage;
    }
    console.log(displayedPlaceholder);
    component.set('v.displayedPlaceholder', displayedPlaceholder);
    component.set('v.placeholder', placeholder);
    component.set('v.noResultsMessage', noResultsMessage);
    console.log('after');
    console.log('placeholder: ' + component.get('v.placeholder'));
    console.log('no results:  ' + component.get('v.noResultsMessage'));
    console.log('displayed:   ' + component.get('v.displayedPlaceholder'));
},

toggle placeholder Patient__c

before

placeholder: - Please Select a Patient -

no results: - No Patients Fit Your Criteria -

displayed: - Please Select a Patient -

SETTING NO RESULTS

after

placeholder: - Please Select a Patient -

no results: - No Patients Fit Your Criteria -

displayed: - Please Select a Patient -

Since the placeholders were only set/changed in this method and within the HTML, I tried changing the HTML. Removing the default="{!v.placeholder}" fixed the issue.

<aura:attribute name="displayedPlaceholder" type="String"  />

It seems like setting displayedPlaceholder's default to placeholder linked their references so that a change to one was reflected in the other. I find this odd for a couple reasons. It's not clear that setting another attribute to v.ANOTHERATTRIBUTE sets the first attribute's value to the second's reference, not value. Secondly, it doesn't make sense that when you set the first attribute's value to the the second attribute's reference, changes to the first attribute affect the second. As far as I understand such relationships, only changes to the second attribute should affect the first.

Does anybody have a good explanation for why this happens? Is this intended functionality, or is it a bug?

2

the way you are passing it its called a bound expression "{!v.placeholder}". Whenever the value of the attribute changes it will change in all the places its referred as well.

If you only want to pass the default value the first time then use a # like "{#v.placeholder}".

This link from lightning components bookshelf explains both in detail.

  • Interesting, I've never read that before but it makes sense. Thanks for the response! – Ryan Dinesman Jun 28 '17 at 16:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.