Picture of sean callahan
Creating buttons for custom components
by sean callahan - Thursday, 29 June 2017, 10:41 PM
 

Hi,

I am playing around with the framework by attempting to create a simple custom component. I started with the blank component example and I've figured out how to add a graphic to it. Now I'm trying to figure out how to get a submit button to show within the component. I've looked at other components and tried to copy what I could see there but it's not clear what needs to be done to add the button.

I've added the buttons div in my handlebars file, and I tried adding this code to my component in components.json:

"_buttons": {
"submit": "Submit"
}

I've also tried referencing the button in my handlebars template by calling it like:

{{{_buttons._submit}}}

I can see that there is an object, but no button yet. I've also tried extending the QuestionView in my javascript file rather than the component view. It doesn't look the the default components need to reference the button in the handlebars file.

I'm assuming once I figure this out I can simply create events connected to functions in my .js file much like I see in other components. Is that correct or are there other steps I should be aware of to connect events to a button press?

I'd appreciate it if you guys point me in the right direction as to how to get this button added to my component.

Code examples:

.hbs file

<div class="component-inner awayMsg-inner">
{{> component this}}
<div class="component-widget awayMsg-widget">
<img src="{{_graphic.src}}" data-large="{{_graphic.large}}" data-small="{{_graphic.small}}"{{#if _graphic.alt}} aria-label="{{_graphic.alt}}" tabindex="0"{{else}} class="a11y-ignore" aria-hidden="true" tabindex="-1"{{/if}}/>
</div>
{{#if _graphic.attribution}}
<div class="graphic-attribution">{{{_graphic.attribution}}}</div>
{{/if}}
<div class="buttons">
{{{_buttons._submit}}}
</div>
</div>

 

.js file

/*
* adapt-component
* License - http://github.com/adaptlearning/adapt_framework/LICENSE
* Maintainers - Daryl Hedley <darylhedley@hotmail.com>
*/

define(["coreViews/componentView", "coreJS/adapt", "coreViews/questionView"], function(ComponentView, Adapt, QuestionView) {

var awayMsg = QuestionView.extend({

events: {
'submit .awayMsgSubmitBtn':'startDemo',
},

startDemo: function(event) {
console.log('start demo');
},

preRender: function() {
this.listenTo(Adapt, 'device:changed', this.resizeImage);

// Checks to see if the graphic should be reset on revisit
this.checkIfResetOnRevisit();
},

postRender: function() {
console.log("rendering");

this.resizeImage(Adapt.device.screenSize, true);

// IMPORTANT!
// Both of the following methods need to be called inside your view.

// Use this to set the model status to ready.
// It should be used when telling Adapt that this view is completely loaded.
// This is sometimes used in conjunction with imageReady.
this.setReadyStatus();

// Use this to set the model status to complete.
// This can be used with inview or when the model is set to complete/the question has been answered.
this.setCompletionStatus();
},


// Used to check if the graphic should reset on revisit
checkIfResetOnRevisit: function() {
var isResetOnRevisit = this.model.get('_isResetOnRevisit');

// If reset is enabled set defaults
if (isResetOnRevisit) {
this.model.reset(isResetOnRevisit);
}
},

inview: function(event, visible, visiblePartX, visiblePartY) {
if (visible) {
if (visiblePartY === 'top') {
this._isVisibleTop = true;
} else if (visiblePartY === 'bottom') {
this._isVisibleBottom = true;
} else {
this._isVisibleTop = true;
this._isVisibleBottom = true;
}

if (this._isVisibleTop && this._isVisibleBottom) {
this.$('.component-widget').off('inview');
this.setCompletionStatus();
}

}
},

remove: function() {
// Remove any 'inview' listener attached.
this.$('.component-widget').off('inview');

ComponentView.prototype.remove.apply(this, arguments);
},

resizeImage: function(width, setupInView) {
var imageWidth = width === 'medium' ? 'small' : width;
var imageSrc = (this.model.get('_graphic')) ? this.model.get('_graphic')[imageWidth] : '';
this.$('.awayMsg-widget img').attr('src', imageSrc);

this.$('.awayMsg-widget').imageready(_.bind(function() {
this.setReadyStatus();

if (setupInView) {
// Bind 'inview' once the image is ready.
this.$('.component-widget').on('inview', _.bind(this.inview, this));
}
}, this));
}
});

Adapt.register("awayMsg", awayMsg);

return awayMsg;

});

 

components.json file: (just the object I added)

{
"_id":"c-05",
"_parentId":"b-05",
"_type":"component",
"_component":"awayMsg",
"_classes":"awayMsgComponent",
"_layout":"center",
"title":"Away Message Component",
"displayTitle":"",
"body":"A showcase for our new away message feature. Now a business can set an away message which will auto-reply to all incoming messages. Click the button below to find out what the message thread would look like when a customer and business interact.",
"instruction":"Click the button to see the away message feature",
"_graphic": {
"large": "course/en/images/iphone_frame_white.png",
"small": "course/en/images/iphone_frame_white.png",
"alt": "iphone graphic",
"attribution": ""
},
"_buttons": {
"submit": "Submit"
}
},

Picture of Matt Leathes
Re: Creating buttons for custom components
by Matt Leathes - Thursday, 29 June 2017, 11:44 PM
 

Hi Sean

If you want to create a button in your component via handlebars you just need to include the html for a button in there:

<div class="buttons">
    <button aria-label="{{_buttons._submit}}">{{_buttons._submit}}</button>
</div>

You can then listen to its click event via the 'events hash' in your js code:

events: {
    'click .buttons button': 'buttonClick'
}

Remember to prevent the default button action (which will cause a page reload) in your event handler function:

buttonClick: function(event) {
    if(event) event.preventDefault();
console.log("button clicked"); }

You don't need to extend questionView - in fact you shouldn't for a component that's not a question.

Picture of sean callahan
Re: Creating buttons for custom components
by sean callahan - Friday, 30 June 2017, 2:56 PM
 

Perfect, exactly the info I needed! Thanks for the insight.

Picture of Matt Leathes
Re: Creating buttons for custom components
by Matt Leathes - Friday, 30 June 2017, 3:46 PM
 

No problem at all. And - apologies if this is already obvious to you but it's tripped me up once or twice: the events hash syntax of 'click .buttons button' is basically saying 'listen to the click event of the <button> element that's inside the element that has a class of buttons'.

Picture of sean callahan
Re: Creating buttons for custom components
by sean callahan - Friday, 30 June 2017, 9:35 PM
 

Yeah I have to admit it took me a couple attempts to figure that out. I added a reset button and classes for both buttons so I could attach different events. At first I was trying to change the .buttons class but then I realized it's a hierarchy of selectors. I've only been fiddling with adapt for a couple days but it's starting to make sense. I've been super deep into jQuery for awhile so I have to reset my thinking a little bit. Thanks for the tip!