Allow users to change language in the Open Event Android app via settings

Localisation of the application is a major step towards maximizing market penetration especially in cases like that of India which houses about 22 official languages. Therefore it is important to allow users to change their language preference from the Open Event Android App itself. There are two different ways through which this could be implemented.

  1. Navigate the user to the phone settings page by firing an implicit intent.
  2. Build an in-app language chooser specific to the country and prompt user to choose language on the first launch of the application.

Out of the two, the open event developers community along the mentors decided to go with the first option since it seemed more apt.

Implementation

In order to implement this, the first and foremost requirement is to keep culture-specific resources separated from the rest of your app. Android resolves language and culture-specific resources based on the system locale setting. Support is provided for different locales by using the resources directory in the Android project. The resources especially the string resources have their own language specific string.xml files and they get resolved with the help of key-value pair mapping. The following steps implement it –

Create a static variable in the application class of the app and assign it the default display language. Make sure to override OnConfigurationChanged method to change the language of the app when the user changes the language.

public class OpenEventApp extends Application {

public static String sDefSystemLanguage;

@Override
public void onCreate() {
 super.onCreate();
 
 sDefSystemLanguage = Locale.getDefault().getDisplayLanguage();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
 super.onConfigurationChanged(newConfig);
 sDefSystemLanguage = newConfig.locale.getDisplayLanguage();
}
}

Include a preference category in your application’s settings.xml which corresponds to the preference activity of the app.

< PreferenceCategory
android: key = “change_language_category”
android: title = “@string/language_preferences” >

< Preference
android: defaultValue = “@string/default_mode_language”
android: key = “@string/language_key”
android: title = “@string/change_language” / >
< /PreferenceCategory>

Finally in your preference activity, set your language preference to the string defined in the application class and implement a click listener on the preference to fire an implicit intent.

public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener {

private Preference languagePreference;
private SharedPreferences preferences;

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 preferences = PreferenceManager.getDefaultSharedPreferences(this);
 addPreferencesFromResource(R.xml.settings);
 setContentView(R.layout.activity_settings);

 languagePreference = findPreference(LANGUAGE_PREF_MODE);
 languagePreference.setSummary(OpenEventApp.sDefSystemLanguage);
}

@Override
public boolean onPreferenceChange(Preference preference, Object o) {

  if (preference.getKey().equals(getResources().getString(R.string.language_key))) {
  languagePreference.setSummary((String) o);
 }

 return false;
}

 @Override
 public void onResume() {
 super.onResume();
 languagePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
  @Override
  public boolean onPreferenceClick(Preference preference) {
   startActivity(new Intent((Settings.ACTION_LOCALE_SETTINGS)));
   return true;
  }
 });

 languagePreference.setSummary(OpenEventApp.sDefSystemLanguage);
}

}

Conclusion

Language can be the greatest asset for an app to reach maximum market capitalisation. It is therefore critical for the apps like open event android to reach scalability for the events to have maximum outreach.

Continue ReadingAllow users to change language in the Open Event Android app via settings

Implementing Session Bookmark Feature in Open Event Webapp

The event websites generated by Open Event Webapp can be large in size with a massive number of sessions in it. As such, it becomes a little difficult for the user to keep track of the sessions he is interested in without any bookmark facility.  With the help of it, he/she can easily mark a session as his favorite and then see them all at once at the click of the button. This feature is available and synchronized across all the pages (track, rooms, and schedule) of the event. That is, if you bookmark a session on the tracks page, it would automatically appear on the other pages too. Likewise, if you unmark a session on any of the page, it would be reflected on rest of the pages.

The event websites generated by the webapp are static in nature. It means that there is no backend server and database where the data about the bookmarked sessions and the user can be stored. So how are we storing information about the marked sessions and persisting it across different browser sessions? There must be a place where we are storing the data! Yes. It’s the LocalStorage Object. HTML5 introduced a localStorage object for storing information which persists even when the site or the browser is closed and opened again. Also, the max size of the localStorage object is quite sufficient (around 5 – 10 MB) for storing textual data and should not be a bottleneck in the majority of the cases.

One very important thing to remember about the localStorage object is that it only supports strings in key and value pairs. Hence, we can’t store any other data type like Boolean, Number or Date directly in it. We would have to convert the concerned object into a string using the JSON.stringify() method and then store it.

Okay, let’s see how we implement the bookmark facility of sessions. We initialize the localStorage object. We create a key in it which is the name of the event and corresponding to its value, we store an object which will contain the information about the bookmarked sessions of that particular event. It’s key will be the id of the session and the value (0 or 1) will define whether it is bookmarked or not. Initially, when no sessions have been bookmarked, it will be empty.

function initPage() {
 //Check whether the localStorage object is already instantiated

 if(localStorage.hasOwnProperty(eventName) === false) {
   localStorage[eventName] = '{}'; // This object will store the bookmarked sessions info
 }
}

Now, we need to actually provide a button to the user for marking the sessions and then link it to the localStorage object. This is the session element with the star-shaped bookmark button

b77bf0d9-7303-4c03-ae29-bd8a4725002b.png

Here is the related code

<a class="bookmark" id="b{{session_id}}">
 <i class="fa fa-star" aria-hidden="true">
 </i>
</a>

Then we need to handle the click event which occurs when the user clicks this button. We will extract the id of the session and then store this info in the event object inside the localStorage object.

$('.bookmark').click(function (event) {
   // Get the event object from the localStorage
   var temp = JSON.parse(localStorage[eventName]);

   // Get the current color of the bookmark icon. If it's black, it means that the session is already bookmarked.
   var curColor = $(this).css("color");

   // Extract the id of the session
   var id = $(this).attr('id').substring(1);

   if (curColor == "rgb(0, 0, 0)") {
     // Unmark the session and revert the font-icon color to default
     temp[id] = 0;
     $(this).css("color", "");
   } else {
     // Bookmark the session and color the font icon black
     temp[id] = 1;
     $(this).css("color", "black");
   }

   localStorage[eventName] = JSON.stringify(temp);
   event.stopPropagation();
 });

So suppose, our event name is FOSSASIA Summit and we bookmarked sessions with the id of 2898 and 3100 respectively, then the structure of the localStorage object will be something like this:-

{'FOSSASIA Summit': { '2898': '1', '3100': '1'}};

To finally show all the bookmarked sessions at once, we defined two modes of the page: Starred and All. In the Starred mode, only the bookmarked sessions are shown. We simply select the event object inside the localStorage and iterate over all the session id’s and only show those which have their value set to 1. In the latter mode, all the sessions are displayed.

Starred Mode (Showing only the bookmarked sessions)

ca1f5fa8-29a2-4b96-8eb1-b22d8b07bda8.png

All Mode (Every session is displayed, both marked and unmarked)

cd23f5f5-4bd1-4d1e-aa96-f4aa28cb5e07.png

References:

Continue ReadingImplementing Session Bookmark Feature in Open Event Webapp

Creating custom cells of table in Open Event Front-end

In the previous post I explained how we extended ember-models-table in

Open Event Frontend for rendering & handling all the table related operations like pagination in the application. In this post we will discuss about how we implemented custom cell layout using custom templates in ember-models-table.

We are going to see how we implemented custom cell layouts in Open Event Front-end.

Creating a custom cell template

The cell templates are partial components which allow us to customise the layout of each cell. We create a component using:

ember g component ui-table/cell/cell-event

The cell-event component renders the image of the event along with its name for all events in the table.

cell-event.hbs

<div class="ui header weight-400">
  <img src="{{record.image}}" alt="Event logo" class="ui image"> {{record.name}}
</div>

Each row from the model is defined as record which represents an event. Here we create a header which consists of an event logo which is referenced as record.image in the model & the event name which is referenced as record.name in the template.

Defining columns & custom templates for each cell of the table

After creating all the templates we must specify which columns should use the cell templates. We can define this inside the columns array of objects(each column) to be rendered in the table. Each object has propertyName which represents the id of the column & title which will be rendered as the table header.

columns: [
  {
    propertyName : 'name',
    template     : 'components/ui-table/cell/cell-event',
    title        : 'Name'
  },
  {
    propertyName : 'startTime',
    template     : 'components/ui-table/cell/cell-date',
    title        : 'Date'
  },
  {
    propertyName : 'roles',
    template     : 'components/ui-table/cell/cell-roles',
    title        : 'Roles'
  },
  {
    propertyName : 'sessions',
    template     : 'components/ui-table/cell/cell-sessions',
    title        : 'Sessions'
  },
  {
    propertyName : 'speakers',
    title        : 'Speakers'
  },
  {
    propertyName : 'tickets',
    template     : 'components/ui-table/cell/cell-tickets',
    title        : 'Tickets'
  },
  {
    propertyName : 'url',
    template     : 'components/ui-table/cell/cell-link',
    title        : 'Public URL'
  }
]

The template field for each column is used to pass the reference of template file which will be used to render the cell of the column. All the cell templates are created in components/ui-table/cell which can be found here.

Rendering the table with cell templates

{{events/events-table columns=columns data=model
  useNumericPagination=true
  showGlobalFilter=true
  showPageSize=true
}}

To render  the table with custom cell templates we need to pass the column array to the extended ember-models-table inside the route as :

The outcome of this change on the cells of column Name now looks like this:

Thank you for reading the blog, you can check the source code for the example here.

Resources

https://semantic-ui.com

https://github.com/onechiporenko/ember-models-table

Continue ReadingCreating custom cells of table in Open Event Front-end

Extending ember-models-table for semantic UI in Open Event Front-end

Open Event Front-end uses ember-models-table for handling all its tables. We chose models-table as there are many tables that are used to display relevant data in the project, which provides features like sorting, searching and pagination common to all table. The ember-models-table allows us handle all such functions using a component.

Although the ember-models-table is great for all kinds of table, it does not support semantic ui which is used in the project. How did you make ember-models-table compatible with semantic ui?

Adding ember-models-table to the project

To add the ember-models-table to the project use:

ember install ember-models-table

Extending the models-table component

The models-table component of the ember-models-table is wrapper which handles all the table functions like search & sort. We extend the models-table component and override the properties of the component.

Create a table component

ember g component ui-table

import Ember from 'ember';
import TableComponent from 'ember-models-table/components/models-table';
import layout from 'open-event-frontend/templates/components/ui-table';

export default TableComponent.extend({
  layout
});

We extend the models-table component by importing it to the ui-table component. We define the layout which is the handlebars template of the table that will be rendered.

<div class="{{classes.outerTableWrapper}}">
  <div class="{{classes.globalFilterDropdownWrapper}}">
    {{#if showPageSize}}
      {{partial pageSizeTemplate}}
    {{/if}}
    {{#if showGlobalFilter}}
      {{partial globalFilterTemplate}}
    {{/if}}
  </div>
  <div class="ui row">
    <div class="{{classes.innerTableWrapper}}">
      <table class="{{classes.table}}">
        <thead class="{{if noHeaderFilteringAndSorting 'table-header-no-filtering-and-sorting'}} {{classes.thead}}">
          {{#if groupedHeaders.length}}
            {{partial headerGroupedRowsTemplate}}
          {{/if}}
          {{partial headerSortingRowTemplate}}
          {{#if useFilteringByColumns}}
            {{partial headerFilteringRowTemplate}}
          {{/if}}
        </thead>
        <tbody>
          {{#if allColumnsAreHidden}}
            {{partial allColumnsHiddenTemplate}}
          {{else}}
            {{#if visibleContent.length}}
              {{#each visibleContent as |record index|}}
                {{#if record}}
                  {{#if (gte index 0)}}
                    {{partial rowTemplate}}
                  {{/if}}
                {{/if}}
              {{/each}}
            {{else}}
              {{partial noDataShowTemplate}}
            {{/if}}
          {{/if}}
        </tbody>
        <tfoot>
          {{partial tableFooterTemplate}}
        </tfoot>
      </table>
    </div>
  </div>
  {{#if showComponentFooter}}
    {{partial componentFooterTemplate}}
  {{/if}}
</div>
{{yield}}

Overriding properties of models-table

The models-table component is not compatible with semantic ui styling, we add the semantic compatibility by overriding the classes of the component & changing it to semantic ui classes. This ensures that the component renders as expected using the semantic ui styled layout.

const defaultCssClasses = {
  outerTableWrapper              : 'ui ui-table',
  columnsDropdown                : 'ui dropdown right'
  pageSizeSelectWrapper          : 'left aligned',
  paginationWrapperNumeric       : 'column four wide',
  paginationWrapperDefault       : 'column four wide',
  buttonDefault                  : 'ui basic button',
  collapseRow                    : 'collapse-row',
  collapseAllRows                : 'collapse-all-rows',
  expandRow                      : 'expand-row',
  expandAllRows                  : 'expand-all-rows',
  clearFilterIcon                : 'remove circle icon',
  globalFilterDropdownWrapper    : 'ui row stackable grid'
};

These classes are use to render all the components of the table.

Adding sub-subcomponents of the models-table

The models-table components uses sub-components which are used to render different sections of the table. We add all the sub-components listed below from here & add it to ui-table.js :

simplePaginationTemplate: 'components/ui-table/simple-pagination',
numericPaginationTemplate: 'components/ui-table/numeric-pagination',
tableFooterTemplate: 'components/ui-table/table-footer',
componentFooterTemplate: 'components/ui-table/component-footer',
pageSizeTemplate: 'components/ui-table/page-size',
globalFilterTemplate: 'components/ui-table/global-filter',
columnsDropdownTemplate: 'components/ui-table/columns-dropdown'

Rendering the ui-table component
For rending the table we need to insert the component using :

{{ui-table columns=columns data=model
  useNumericPagination=true
  showGlobalFilter=true
  showPageSize=true
}}

The outcome of this change on the Open Event Front-end now looks like this:

Thank you for reading the blog, you can check the source code for the example here.

Resources:

Continue ReadingExtending ember-models-table for semantic UI in Open Event Front-end

Creating sponsors layout in Open Event Front-end

In this blog I discuss how we implemented sponsors layout in Open Event Front-end. The sponsors are fetched from Orga Server API and is handled using Ember JS in the Front-end.

The fetched sponsor is an array of JSON objects which need to be grouped based on the type of the sponsor which is done using the lodash library. How do we implement it?

Creating sponsor-list & sponsor-item components

We create two components sponsor-list which contains all the sponsors & sponsor-item which is used to render each sponsor.

ember g component sponsor-list

ember g component sponsor-item

Grouping the sponsors by type

The API response return an array of the sponsors of the event as :

 sponsors: [
   { name: 'Sponsor 2', 
     Url: '#', 
     logoUrl: 'http://placehold.it/150x60', 
     level: 2, 
     type: 'Gold Sponsor', 
     description: '' 
   }, 
   { name: 'Sponsor 1', 
     url: '#', 
     logoUrl: 'http://placehold.it/150x60', 
     level: 1, 
     type: 'Silver Sponsor', 
     description: '' 
   }
 ]

This response is the list of all sponsors, which is not grouped by the type of the sponsor. We sort and group the array and return a JSON object in the sponsor-list component.

import Ember from 'ember';
import { orderBy, groupBy } from 'lodash';

const { Component, computed } = Ember;

export default Component.extend({

 sponsorsGrouped: computed('sponsors.[]', function() {
   return groupBy(orderBy(this.get('sponsors'), 'level'), 'type');
 })
});

We use lodash orderBy to sort the sponsors by the level and groupBy to convert the array into an JSON object of the grouped sponsors. We compute the grouped object using ember computed property.

Rendering sponsors in public event route

The sponsor array is passed to the sponsors-list component where the sponsors are sorted and grouped. We pass each sponsor from the sponsorsGrouped to the sponsor-item component which renders the logo of the sponsor.

sponsor-list.hbs

<h3 class="ui header">{{t 'Sponsors'}}</h3>
{{#each-in sponsorsGrouped as |key sponsors|}}
 <h4 class="ui header">{{key}}</h4>
 <div class="ui three column stackable grid">
   {{#each sponsors as |sponsor|}}
     {{public/sponsor-item sponsor=sponsor}}
   {{/each}}
 </div>
{{/each-in}}

sponsor-item.hbs

<a href="{{sponsor.url}}">
 <img src="{{sponsor.logoUrl}}" class="ui image  sponsor-image" alt="{{sponsor.name}}">
</a>

The outcome of this change on the Open Event Front-end now looks like this:

Thank you for reading the blog, you can check the source code for the example here.

Resources:

 

Continue ReadingCreating sponsors layout in Open Event Front-end

Data Scraping using Python with BeautifulSoup4 for Open Event samples

was creating samples for Open Event Android and Open Event Webapp when the idea of web scraping through scripts stuck me.

I chose Python for web scraping. But what’s more to using Python other than it’s user-friendliness, easy syntax and speed? It’s the wide variety of open-source libraries that come along with it!

One of them is the BeautifulSoup library for extracting data from XML and HTML tags and files. It provides with ways to search and sort through webpages, find specific elements that you need and extract them in objects of your preference.

Apart from BeautifulSoup, another module that can be easily neglected but is of great use is:- urllib2. This module is to open URLs that are fed to it.

Hence, with a combination of the above 2 Python modules, I was able to scrape off the main sample data like speakers, sessions, tracks, sponsors and so on for PyCon 2017 (sample that I created recently) in a quicker and more efficient way.

I will now talk about these modules in greater detail and their use in my web scraping scripts.

Web Scraping with BeautifulSoup

Start by installing Beautifulsoup module in your Python environment. I believe that it will be best to install it using  pip.  Run the following command to install Beautifulsoup:-

pip install beautifulsoup4

Next up, you need to import the module to your script by adding the following line:-

from bs4 import BeautifulSoup

Now you need to open a webpage using the module in the following way. For that we first have to open the URL of the page that is being scraped. We use urllib2 to do that.

import urllib2
site=urllib2.urlopen("https://us.pycon.org/2017/sponsors/")

Next we use BeautifulSoup to get the contents of the webpage in the following way:-

website=BeautifulSoup(site)

Suppose that, next I want to obtain the data inside all the <div> tags in the webpage that have their class=”sponsor-level”.

I will use BeautifulSoup in the following way along with the ‘find_all’ method to do so :-

divs=website.find_all("div",{'class':'sponsor-level'})

Here, divs will now be a special <list> type element containing all the HTML in the div tags of class=’sponsor-level’. Now I can do whatever with I want with this list. Parse it in any way, store it any kind of data type without any difficulty.

BeautifulSoup also helps in accessing the children tags or elements of different HTML or XML tags using the ‘dot’ (.) operator. Following example will make it more clear:-

tag = soup.b

Here, ‘tag’ will contain all the  <b> elements of the parent element that is stored in ‘soup’ variable.

To access attributes of HTML or XML tags, there is a special way as demonstrated below:-

To access the ‘href’ attribute of the first <a> tag in the webpage:-

soup.find_all(“a”)[0][‘href’]

A sample script…

Following is a script that I used to obtain sponsors from the PyCon 2017 site in json format.

import urllib2

site=urllib2.urlopen("https://us.pycon.org/2017/sponsors/")

from bs4 import BeautifulSoup

s=BeautifulSoup(site)

divs=s.find_all("div",{'class':'sponsor-level'})

spons=[]

for level in divs:

levelname=level.find_all("h2")[0].string

level_sponsors=level.find_all("div",{'class':'sponsor'})

for level_sponsor in level_sponsors:

anchor=level_sponsor.find_all("a")

dictionary={}

dictionary['id']=""

dictionary['name']=anchor[1].string

dictionary['level']=""

dictionary['sponsor_Type']=levelname

dictionary['url']=anchor[0]['href']

dictionary['description']=level_sponsor.find_all("p")[1].string

spons.append(dictionary)

print spons

There are still a lot of other functionalities of BeautifulSoup that are available and can make your life easier. These can be found here in the official BeautifulSoup documentation.

Continue ReadingData Scraping using Python with BeautifulSoup4 for Open Event samples

Implementing PNG Export of Schedule in Open Event Webapp

Fortunately for us, we don’t have to implement it from scratch (which would have been extremely difficult and time-consuming). Enter html2canvas library. It renders an element onto the canvas after which we can convert it into an image. I will now explain how we implemented png export in the calendar mode. You can view the whole schedule template file here

Here is a screenshot of calendar or grid view of the schedule. Currently selected date is 18th Mar, Saturday. The PNG Export button is on the top-right corner beside the ‘Calendar View’ button.

32fa6d15-59da-4521-b348-6c01f6af7825.png

Here is a little excerpt of the basic structure of the calendar mode of the sessions. I have given an overview of it in the comments.

<div class="{{slug}} calendar">
 <!-- slug represents the currently selected date -->
 <!-- This div contains all the sessions scheduled on the selected date -->
 <div class="col-md-12 paddingzero">
   <!-- Contain content related to current date and time -->
 </div>
 <div class="calendar-content">
   <div class="times">
     <!-- This div contains the list of all the session times on the current day -->
     <!-- It is the left most column of the grid view which contains all the times →
     <div class="time">
       <!-- This div contains information about the particular time -->
     </div>
   </div>
   <div class="rooms">
     <!-- This div contains all the rooms of an event -->
     <!-- Each particular room has a set of sessions associated with it on that particular date -->
     <div class="room">
       <!-- This div contains the list of session happening in a particular room -->
       <!-- Session Details -->
     </div>
   </div>
 </div>
</div>

Now, let us see how we will actually capture an image of the HTML element shown above. Here is the code related to it:

$(".export-png").click(function() {
 if (isCalendarView === true) {

   $('.calendar').each(function() {
     if ($(this).attr('class').split(' ').indexOf('hide') <= 0) {

       $timeline = $(this);
       initialWidth = $timeline.width();
       numberOfChildElements = $timeline.find('.rooms')[0].childElementCount;
       numberOfChildElements = numberOfChildElements - 1;
       widthOfChild = $timeline.find('.room').width();
       canvasWidth = numberOfChildElements * widthOfChild + 50;
       $timeline.width(canvasWidth);
     }
   });
 }

 html2canvas($timeline, {
   onrendered: function(canvas) {
     canvas.id = "generated-canvas";
     canvas.toBlob(function(blob) {
       saveAs(blob, '' + $timeline.attr('class') + '.png');
     });
   },
 });
 $timeline.width(initialWidth);
});

Note that this initial width calculated is the width which is visible to us on the screen. In reality, the element might be scrollable and its actual width might be different. If we render the element using the initial width, we would not be able to see the full contents of that element. It will not show the whole view. Hence we need to calculate the actual width.Let us see what is going on in this code. When the user clicks on the export PNG button, we check whether we are in the calendar mode or not. If yes, then we proceed further. We then see which date is currently selected and accordingly select that div. After selecting it, we then get the initial width of that element.

So, we check all the child elements inside it, get their count and width and then calculate the actual width of the parent element based on it. Temporarily, we set this actual width as the width of the session element and pass it to the html2canvas function. That in turn, renders the whole element onto a canvas. After it has been successfully rendered onto the canvas, we save it to as an image and present a download box to the user for downloading that image.

Here is the download pop-up box

bfbd12c2-f6ed-4dae-8485-bfd1638faf74.png

And this is the downloaded PNG Image. Click on it for a higher resolution!

Screenshot from 2017-07-03 00-31-56.png

Resources

Continue ReadingImplementing PNG Export of Schedule in Open Event Webapp

Creating a component for achieving an n-times running loop in Open Event Frontend

This blog article will illustrate how to to make a component in ember JS which allows you to iterate over a block of statements n-times which is being used in Open Event Frontend This is of great utility as the default ‘each’ helper of ember only allows us to iterate over objects and arrays, and not simply as a loop.So we begin by generating a component and calling it `n-times` and it is currently being used in the open event front-end project.

Even before implementing it, it is obvious to us that the content inside the loop can be any thing and the component should be able to iterate over them repeatedly. Thus this component will need to have a {{yield}} block inside it, and thus will always have to be used in block form, to allow the user to enter the content that we need to iterate over.
We begin by simply generating the boiler plate code of the component via Ember CLI.

$ ember generate component n-times

Now we proceed with the js code of the component. The only thing we need to ensure here is that no extra html tags are introduced because of our component, else it might break the flow of tags or disrupt the styling. Hence we make use of the tagName property to achieve the same.
The final code looks something like this:

import Ember from 'ember';

const { Component } = Ember;

export default Component.extend({
 tagName: ''
});

We just needed to make the tagName none as we don’t want an extra div. And this is the template code for the same component
For the template part we simply enclose the {{yield}} block inside each loop, and the value of times is expected to be passed at the time of calling the component.

{{#each (range 0 times) as |number|}}
{{yield number}}
{{/each}}

An important thing to note, we cannot have made this as a helper because the block form of helpers has been deprecated since Ember has updated hence component was the obvious choice.

This may now be simply used as

{{#n-times times=5}}

{{ui-checkbox label=(t 'Create')}}

{{ui-checkbox label=(t 'Read')}}

{{ui-checkbox label=(t 'Update')}}

{{ui-checkbox label=(t 'Delete')}}

{{/n-times}}

 

Resources

*Featured image is captured by the author of this post, it is under public domain without any restrictions.

Continue ReadingCreating a component for achieving an n-times running loop in Open Event Frontend

Using ember semantic UI radio buttons to render form elements selectively on Open Event Front End

This blog article will illustrate how ember semantic ui radio buttons have been used to render form elements selectively on Open Event Front End and in the process will learn, how to make use of the powerful binding features offered by ember semantic ui for radio buttons via the mut action.

So what do we have to begin with ?

The sample form which we want to create

A form which allows us to chose one of the modes of Paypal payments and displays corresponding fields for it.

What we want is that the radio button should allow us to make a choice and then display the corresponding  fields. Now that seems a trivial process, but there is some thought process which goes into this, to end up with the most efficient choice. So first just make the basic form where in all the fields are visible.

Now let’s learn how to make use of the mut action on the radio buttons. What it allows us to do is pass a parameter while calling it, and that parameter name is shared by all the radio buttons belonging to a particular group of radio buttons. And what that action does is, store the name of the currently selected radio button in it. So we can easily keep track of which button has been selected and use that variable in selective rendering of templates. The action is triggered whenever the radio button’s property changes and the trigger is aptly called onChange. So essentially the syntax boils down to this :

<!-- The first radio button -->
{{ui-radio label=(t 'Sandbox mode - Used during development and testing')
           name='paypal_integration_mode'
           value='sandbox'
           onChange=(action (mut selectedMode))}}
<!-- The second radio button -->
{{ui-radio label=(t 'Live mode - Used during production') 
           name='paypal_integration_mode'
           value='live'
           onChange=(action (mut selectedMode))}}

Now whichever button is selected it’s name will be stored in selectedMode in this case. And hence we can use the conditional helpers of handle bars to render elements based on the selected radio button.

The final code looks something like this:

  <.h3 class="ui header">{{t 'PayPal Credentials'}}<./h3>
    <.div class="sub header">
       {{t 'See here on how to obtain these keys.'}}
    <./div>
   <.h5 class="ui header">{{t 'PayPal Integration Mode'}}<./h5>
   <.div class="field">
     {{ui-radio label=(t 'Sandbox mode')
                name='paypal_integration_mode' 
                value='sandbox' 
                current='sandbox'
                onChange=(action (mut selectedMode))}}
   <./div>
   {{#unless (eq selectedMode 'live')}}
     <.div class="field">
       <.label>{{t 'Sandbox username'}}<./label>
       {{input type='text' name='sandbox_username'}}
     <./div>
     <.div class="field">
       <.label>{{t 'Sandbox password'}}<./label>
       {{input type='password' name='sandbox_password'}}
     <./div>
     <.div class="field">
       <.label>{t 'Sandbox signature'}}<./label>
       {{input type='text' name='sandbox_signature'}}
     <./div>
   {{/unless}}
   <.div class="field">
     {{ui-radio label=(t 'Live mode')
                name='paypal_integration_mode'
                value='live' 
                onChange=(action (mut selectedMode))}}
   <./div>
   {{#if (eq selectedMode 'live')}}
     <.div class="field">
      <.label>{{t 'Live username'}}<./label>
       {{input type='text' name='live_username'}}
     <./div>
     <.div class="field">
       <.label>{{t 'Live password'}}<./label>
       {{input type='password' name='live_password'}}
     <./div>
     <.div class="field">
       <.label>{{t 'Live signature'}}<./label>
       {{input type='text' name='live_signature'}}
     <./div>
   {{/if}}
   <.button class="ui teal button" type="submit">
   {{t 'Save'}}
   <./button>

 

Important tip

The action is triggered by the onChange action, hence the variable doesn’t have the value when the template is rendered for the very first time and hence at that instant, none of the fields will be rendered, to avoid that we have used both if and unless condition helpers instead of identical conditional helpers to cleverly avoid this situation. You can read about the ember radio buttons further more through the official documentation

Resources

Continue ReadingUsing ember semantic UI radio buttons to render form elements selectively on Open Event Front End

Making currency name and currency symbol helpers for Open Event Frontend

This blog article will illustrate how to make two helpers which will help us in getting the currency name and symbol from a dictionary, conveniently.The helpers will be used as  a part of currency form on Open Event Front End It also exemplifies the power of ember JS and why is it being used in this project via a counter example in which we try to do things the non ember way and get the required data without using those helpers.

So what do we have to begin with ?

The sample data which will be fetched from the API:

[
     {
       currency   : 'PLN',
       serviceFee : 10.5,
       maximumFee : 100.0
     },
     {
       currency   : 'NZD',
       serviceFee : 20.0,
       maximumFee : 500.0
     }
     //The list continues
]

The dictionary data format:

[
  {
    paypal : true,
    code   : 'PLN',
    symbol : 'zł',
    name   : 'Polish zloty',
    stripe : true
  },
  {
    paypal : true,
    code   : 'NZD',
    symbol : 'NZ$',
    name   : 'New Zealand dollar',
    stripe : true
  },
  {
    paypal : false,
    code   : 'INR',
    symbol : '₹',
    name   : 'Indian rupee',
    stripe : true
  }
]
// The list continues

And our primary goal is to fetch the corresponding name and symbol from the dictionary for a given currency code, easily and efficiently.

One might be tempted to get things done the easy way : via

{{get (find-by 'code' modal.name currencies) 'name'}}

and perhaps,

{{get(find-by 'code' modal.name currencies) 'symbol'}}

where currencies is the name of the imported array from the dictionary. But this might be hard to follow for a first time reader, and also in case we ever need this functionality to work in a different context, this is clearly not the most feasible choice. Hence helpers come into picture, they can be called anywhere and will have a much simpler syntax

Our goal is to make helpers such that the required functionality is achieved with a simpler syntax than the one shown previously.So we will simply generate the helpers’ boiler-plate code via ember CLI

$ ember generate helper currency-name
$ ember generate helper currency-symbol

Next we will import the currency format from the payment dictionary to match it against the name or symbol provided by the user. Now all that remains is finding the correct matching from the dictionary. We import the find function from lodash for that.

So, this is how they would look

import Ember from 'ember';
import { find } from 'lodash';
import { paymentCurrencies } from 'open-event-frontend/utils/dictionary/payment';

const { Helper } = Ember;

export function currencyName(params) {
  return find(paymentCurrencies, ['code', params[0]]).name;
}

export default Helper.helper(currencyName);

 

And for the currency symbol helper

import Ember from 'ember';
import { find } from 'lodash';
import { paymentCurrencies } from 'open-event-frontend/utils/dictionary/payment';

const { Helper } = Ember;

export function currencySymbol(params) {
  return find(paymentCurrencies, ['code', params[0]]).symbol;
}

export default Helper.helper(currencySymbol);

 

Now all we need to do use them is {{currency-name ‘USD’}} and {{currency-symbol ‘USD’}} to get the corresponding currency name and symbol. We use find from lodash here instead of the default even though it is similar in performance because it provides much better readability.

Resources

*Featured Image licensed under Creative Commons CC0 in public domain

Continue ReadingMaking currency name and currency symbol helpers for Open Event Frontend