File Upload Validations on Open Event Frontend

In Open Event Frontend we have used semantics ui’s form validations to validate different fields of a form. There are certain instances in our app where the user has to upload a file and it is to be validated against the suggested format before uploading it to the server. Here we will discuss how to perform the validation.

Semantics ui allows us to validate by facilitating pass of an object along with rules for its validation. For fields like email and contact number we can pass type as email and number respectively but for validation of file we have to pass a regular expression with allowed extension.The following walks one through the process.

fields : {
  file: {
    identifier : 'file',
    rules      : [
      {
        type   : 'empty',
        prompt : this.l10n.t('Please upload a file')
      },
      {
        type   : 'regExp',
        value  : '/^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i',
        prompt : this.l10n.t('Please upload a file in suggested format')
      }
    ]
  }
}

Here we have passed file element (which is to be validated) inside our fields object identifier, which for this field is ‘file’, and can be identified by its id, name or data-validate property of the field element. After that we have passed an array of rules against which the field element is validated. First rule gives an error message in the prompt field in case of an empty field.

The next rule checks for allowed file extensions for the file. The type of the rule will be regExp as we are passing a regular expression which is as follows-

/^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i

It is little complex to explain it from the beginning so let us breakdown it from end-

 

$ Matches end of the string
[^.]* Negated set. Match any character not in this set. * represents 0 or more preceding token
( … )? Represents if there is something before (the last ?)
.*.((zip|xml|ical|ics|xcal)$) This is first capturing group ,it contains tocken which are combined to create a capture group ( zip|xml|ical|ics|xcal ) to extract a substring
^ the beginning of the string

Above regular expression filters all the files with zip/xml/ical/xcal extensions which are the allowed format for the event source file.

References

  • Ivaylo Gerchev blog on form validation in semantic ui
  • Drmsite blog on semantic ui form validation
  • Semantic ui form validation docs
  • Stackoverflow regex for file extension
Continue Reading

Adding Settings and Contact Info Route to Open Event Frontend

In Open Event Frontend, while dealing with an issue, we had to create the ‘contact-info’ route as a subroute of the ‘settings’ route. We have given the user a facility to update his/her information thereby allowing them to change it whenever they want.

Thus to generate the route, we are using ember cli:

ember g route settings/contact-info

Thus, the above command will generate three files:

  • routes/settings/contact-info.js
  • templates/settings/contact-info.hbs
  • tests/unit/routes/settings/contact-info-test.js

1) contact-info.hbs

In this file, we have a form which we have made a component for easy use. Thus following is the content of the contact-info.hbs file:

{{settings/contact-info-section}}

Thus ultimately, we are having a component called ‘contact-info-section’ which contains our markup for the contact-info form.
To generate the component, we do:

ember g component settings/contact-info-section

This command will generate two files:
1. templates/components/contact-info-section.hbs
2. components/contact-info-section.js

Following is the markup in contact-info-section.hbs:

<form class="ui form" {{action 'submit' on='submit'}} novalidate>
  <div class="field">
    <label>{{t 'Email'}}</label>
    {{input type='email' name='email' value=email}}
  </div>
  <div class="field">
    <label>{{t 'Phone'}}</label>
    {{input type='text' name='phone' value=phone}}
  </div>
  <button class="ui teal button" type="submit">{{t 'Save'}}</button>
</form>

In the form, we are having two fields for inputs ‘Email’ and ‘Phone’ respectively. We are using Ember input helpers so as to achieve easy data binding. The name is used as an identifier for the validation.
We have one submit button at the bottom which saves the information that the user wants to update.

The contact-info-section.js file contains all the validation rules which validate the form when the user submits it. If a user enters any field empty, the form prompts the user with a message. Following is an example of the validation rules for the email field:

email: {
          identifier : 'email',
          rules      : [
            {
              type   : 'empty',
              prompt : this.l10n.t('Please enter your email ID')
            },
            {
              type   : 'email',
              prompt : this.l10n.t('Please enter a valid email ID')
            }
          ]
        }

Similar rules are there for the ‘phone’ field input.

2) contact-info.js
The contact-info.js renders our route. Thus it contains the ‘titletoken’ method which returns the ‘titletoken’ method which returns the page title.

Thus, after doing all the things above, we get the following as a result.

Resources:

Source code: https://github.com/fossasia/open-event-frontend

Continue Reading

Using Semantic UI Modals in Open Event Frontend

Modals in semantic UI are used to display the content on the current view while temporarily blocking the interaction with the main view. In Open Event Frontend application, we’ve a ‘delete’ button which deletes the published event as soon as the button is pressed making all the data clean. Once the event is deleted by the user, it is not possible to restore it again. We encountered that this can create a whole lot of problem if the button is pressed unintentionally. So we thought of solving this by popping up a dialog box on button click with a warning and asking for user’s confirmation to delete the event. To implement the dialog box, we used semantic UI modals which helped in ensuring that the user correctly enters the name of the event in the given space to ensure that s/he wants to delete the event.

Since we want our modal to be customizable yet reusable so that it can be used anywhere in the project so we made it as the component called ‘event-delete-modal’. To do that we first need to start with the template.

The markup for the event-delete-modal looks like this:

<div class="content">
  <form class="ui form" autocomplete="off" {{action (optional formSubmit) on='submit' preventDefault=true}}>
    <div class="field">
      <div class="label">
        {{t 'Please enter the full name of the event to continue'}}
      </div>
      {{input type='text' name='confirm_name' value=confirmName required=true}}
    </div>
  </form>
</div>
<div class="actions">
  <button type="button" class="ui black button" {{action 'close'}}>
    {{t 'Cancel'}}
  </button>
  <button type="submit" class="ui red button" disabled={{isNameDifferent}} {{action deleteEvent}}>
    {{t 'Delete Event'}}
  </button>
</div>

The complete code for the template can be seen here.

The above code for the modal window is very similar to the codes which we write for creating the main window. We can see that the semantic UI collection “form” has also been used here for creating the form where the user can input the name of the event along with delete and cancel buttons. The delete button remains disabled until the time correct name of the event been written by the user to ensure that user really wants to delete the event. To cancel the modal we have used close callback method of semantic UI modal which itself closes it. Since the ‘isNameDifferent’ action is uniquely associated to this particular modal hence it’s been declared in the ‘event-delete-modal.js’ file.

The code for the  ‘isNameDifferent’ in ‘event-delete-modal.js’ file looks like this.

export default ModalBase.extend({
  isSmall         : true,
  confirmName     : '',
  isNameDifferent : computed('confirmName', function() {
    return this.get('confirmName').toLowerCase() !== this.get('eventName').toLowerCase();
  })
});

The complete code for the.js file can be seen here.

In the above piece of code, we have isSmall variable to ensure that our modal size is small so it can fit for all screen sizes and we have the implementation isNameDifferent() function. We can also notice that our modal is extending the ‘ModelBase’ class which has all the semantic UI modal settings and the callback methods to perform show, hide, close and open actions along with settings which will help modal to look the way we want it to be.  

The modal-base.js class looks like this.

  openObserver: observer('isOpen', function() {
   close() {
     this.set('isOpen', false);
   },
   actions: {
    close() {
      this.close();
    }
  },
  willInitSemantic(settings) {
    const defaultOptions = {
      detachable     : false,
      duration       : testing ? 0 : 200,
      dimmerSettings : {
        dimmerName : `${this.get('elementId')}-modal-dimmer`,
        variation  : 'inverted'
      },
      onHide: () => {
        this.set('isOpen', false);
        if (this.get('onHide')) {
          this.onHide();
        }
      },
      onVisible: () => {
        this.set('isOpen', true);
        this.$('[data-content]').popup({
          inline: true
        });
     }

The complete code for the .js file can be seen here.

In the above code, we can see that at the top we’ve an ‘openObserver’ function where we’re observing the behaviour of the modal and setting the variables according to the behavioural changes. Now, later we’re checking the status of those variables and performing the actions based on their value. For example, to close the modal we have a boolean variable ‘isOpen’ which is set to false now close() action will be called which closes the modal.  Similarly, in ‘willInitSemantic(settings)’ function we’re setting the modal’s setting like the effects, length, the details modal will display on popping out etc.
We’re here overriding the semantic UI moda settings like detachable, dimmerSettings, duration etc along with the callback methods like onHide(), onVisible() etc. to get the required results.

Finally, our event-delete-modal will look something like this.

Fig: Modal to delete the event

So to conclude this post, we can easily say that the modals are of great use. They can solve the purpose of displaying some alert or to input some values without interrupting the flow of the main page depending upon the requirements.

Additional Resources:

Blog post about Awesome Ember.js Form Components of Alex Speller: http://alexspeller.com/simple-forms-with-ember/

Continue Reading
Close Menu