gwalshington gwalshington - 17 days ago 6
jQuery Question

JS function undefined when calling from certain click events in handlebars template

I am not understanding why the function goToProfile(otherUserId) is 'not defined' only some of the times.

For example, on the page, I have a link to a user that works fine by using the '.userProfileLink' click event.

<%= link_to image_tag(user.avatar.url(:medium)), "/profile/#{user.id}/view", class: "userProfileLink", :"value" => user.id, remote: true %>


Then I click #requestMeeting which renders this handlebars template:

<script id="request-meeting-form" type="text/x-handlebars-template">


<form id="requestMeetingForm">
<div class="form_section">

<h4 style="text-align:center;">Request 1 Hour Meeting</h4>
<br>
<div class="wrapper_input col_8_of_16">

<h4 class="label_standard">Date</h4>

<input type="text" id="meeting_date" class="input_standard datePicker" onfocus="this.blur()"></input>

<input type="hidden" id="alt_meeting_date" class="input_standard datePicker"></input>

</div>

<div class="wrapper_input col_4_of_16">

<h4 class="label_standard">Start Time</h4>
<input type="text" id="meeting_time" class="input_standard time_picker" onfocus="this.blur()"></input>

</div>


</div>

<div class="form_section">


<div class="wrapper_input">
<a href="#" type="button" id="suggestedLocations" class="btn_secondary" >Find a place to meet <svg class="chat"><use xlink:href="#map"/></use></svg></a>
</div>
<br>
<div class="wrapper_input col_8_of_16">
<input type="text" name="location" id="locationField" placeholder="Location Name" class="input_standard" ></input>
</div>{{!--
--}}<div class="wrapper_input col_8_of_16">
<input type="text" name="location_address" id="addressField" placeholder="Location Address" class="input_standard"></input>
</div>


<input type="hidden" id="currentUser"></input>


</div>

<div id="mapLocation">

</div>
**************** IMPORTANT PART *********************

<div class="form_section submit_cancel">
<div class="wrapper_input cancel" >
<a href='#' class="link_cancel" id="goToProfile" value={{userId}}>Cancel<svg class="meeting_cancel"><use xlink:href="#circleClose"/></svg></a>
</div>

********************************************
<div class="wrapper_input submit">
<div class="actions">
<button type="submit" class="btn_primary" id="requestMeetingButton" >Request Meeting <svg class="" ><use xlink:href="#sendPlane"/></svg></button>
</div>

</div>
</div>
</form>


</script>


When I try to call goToProfile again in the template above, I get an error that goToProfile is not defined.

application.js:

$(document).on('click', '#goToProfile', function(e) {
e.preventDefault();
var value = $(this).attr('value')
var otherUserId = parseInt(value);
$('#profileSection').empty();
goToProfile(otherUserId);
});


var ready;

ready = function(){


var currentUserId;
getCurrentUser().done(function() {
var currentUserId = currentUserId
});

$('.userProfileLink').click(function(e) {
var value = $(this).attr('value')
otherUserId = value;
goToProfile(otherUserId);

});



var profileSource = $("#user-profile").html();
var compiledProfile = Handlebars.compile(profileSource);

var languageSource = $("#languages").html();
var compiledLanguage = Handlebars.compile(languageSource);
var language = ""

var currentUserId;

var goToProfile = function(otherUserId) {
$.ajax({
url: '/get_user',
type: 'GET',
data: {otherUserId: otherUserId},
success: function(user) {
var profileInfo;
getUserImage(otherUserId).done(function() {
var profileInfo = {
first_name: user.first_name,
location: user.location,
bio: user.bio,
nationality: user.nationality,
userId: user.id,
userImage: userImage,

};
var profileTemplate = compiledProfile(profileInfo);
$('.yieldedInfo').empty();
$('.yieldedInfo').append('<div class="profileContainer">' + profileTemplate + '</div>');
});

getLanguagesUsers(user.id);

$('#requestMeeting').click(function(e) {
e.preventDefault();
requestMeetingForm(this.value);

});
},
error: function(err) {
console.log(err);
}
});

};



var getLanguagesUsers = function(userId) {
$.ajax({
url: '/user_languages',
type: 'GET',
data: {userId: userId},
success: function(languages) {
for(var i=0; i<languages.length; i++) {

if(languages[i].level != 5) {
var id = languages[i].language_id
var langUrl = '/languages/'+id;
$.getJSON(langUrl, function(lang) {
var language = lang.language

var languageInfo = {
language: language
};
var languageTemplate = compiledLanguage(languageInfo);
$('#learningLanguages').append(languageTemplate);

});

} else {
var id = languages[i].language_id;
var langUrl = '/languages/'+id;
$.getJSON(langUrl, function(lang) {
var language = lang.language
var languageInfo = {
language: language
};
var languageTemplate = compiledLanguage(languageInfo);
$('#fluentLanguages').append(languageTemplate);
});
};
};

},
error: function(err) {
console.log(err);
}
});
};




};

$(document).ready(ready);
$(document).on('page:load', ready);


How can I make goToProfile() available to be called all the time?
Thanks!

Answer

You can do what you need by binding the click event handler at the same scope level as the function it needs to call...

var ready = function(){

    $(document).on('click', '#goToProfile', function(e) {
        e.preventDefault();
        var value = $(this).attr('value')
        var otherUserId = parseInt(value);
        $('#profileSection').empty();
        goToProfile(otherUserId);
    });

    // the rest of your ready function goes here

};

If you do it that way then the event handler has access to the goToProfile function as they're both within the ready function. Nothing outside that function can access the private methods inside it.