DVelum 0.9.2.7 New Opportunities Inheriting components, creating events, using embedded projects. Geo search component case study

This case study demonstrates the platform new opportunities and provides an insight into object inheritance, method and event creation. It also tackles some aspects of work with Google Maps API, as well as connecting external plugins and embedded projects.

Case description

DB creation

Interface creation

Creating the Map Component

Connecting Component to the Project

Case Description

Let’s try implementing an interface, which contains a list of users with their geo location coordinates. The entry manager should allow indicating user name and geo location coordinates, while the geo location coordinates are added by click on the map.

DB Creation

Enter the ORM management interface and create a new object - geouser, which will contain user name and geo location data in the following fields.

  • name - varchar 255
  • latitude - decimal (12.6)
  • longitude - decimal (12.6)

Interface Creation

Enter the Admin panel module manager and create a module for geouser object:

Check the interface created by the system:

Now, you need to enhance the user editor so that coordinates could be added by click on the map.

Using the Layout Designer, create an independent component, which will define the coordinates.

Creating the Map Component

Enter the Layout Designer and create a component project, name it ‘map’ and get down to adjusting the project settings. Change the namespaces:

  • Project classes namespace: appMapClasses
  • Project run namespace: appMapRun

For working with maps, you’ll need JS plugin, which is already there in the system - js/lib/ext4/ux/GMapPanel.js. Connect it to the project (see the related documentation here: http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.ux.GMapPanel).

Add a window to the project and name “mapWindow”.

Use the platform new opportunities and declare the window to inherit from Ext Window. To do so, set the property isExtended to true, thus making it possible to define the inherent events and methods.

Change the layout property as well: layout: fit.

Now, you need to add the component displaying the map to the window. As the Designer doesn’t have such a component, you’ll need to initialize in manually.

First of all, connect Google map API in the project’s actionJS. Open the JS code editor and insert the dynamic loader API:

Ext.onReady(function(){
  Ext.Loader.loadScriptFile('https://www.google.com/jsapi',
   function(){
       google.load("maps", "3", {
             other_params:"sensor=false",
             callback : function(){
                    // Google Maps are loaded. Place your code here
             }
       });
    } , Ext.emptyFn , null , false);
});

Now, we need to initialize the UX-component and add several methods to the mapWindow.

Redefine the initComponent method of the mapWindow.

Get to the methods tab of the property panel and press the “Add Method” button. Specify initComponent in the window requesting the name of the new method.

The method will contain the following code:

// selected address coordinates	
this.selectedLatLng = false;
// the array of map markers for the ease of operation
this.markersArray = [];
// initialize the component Ext.ux.GMapPanel, add 
// 'mapready' event handler. Once the map is initialized, 
// prepareMap method described in mapWindow 
// is called
this.gmapPanel = Ext.create('Ext.ux.GMapPanel',{
         center: {
            geoCodeAddr: '4 Yawkey Way, Boston, MA, 02215-3409, USA'
        },
        listeners:{
              'mapready':{
                 fn:this.prepareMap,
                 scope:this
              }
        }
});
// invoke rendering of components assigned in the Designer,
// which is necessary as you have redefined 
// the initComponent responsible for this process
this.addDesignerItems();

if(Ext.isEmpty(this.items)){
    this.items = [];
}
//  add the map panel to the window
this.items.push(this.gmapPanel);
//  transfer handling to the initComponent  of the parent object
this.callParent();

Add two system methods for managing markers:

removeMarkers (removing markers from the map) Code:

// review the markers list and disable them	  	 	
for (var i = 0; i < this.markersArray.length; i++ ) {
    this.markersArray[i].setMap(null);
}
// clear markers list
this.markersArray = [];

addMarker (adding a marker to the map) Parameters: float lat , float lng Code:

// create a new google map API coordinate object
var myLatlng = new google.maps.LatLng(lat,lng);
// create a google map API marker
var marker = new google.maps.Marker({
   position: myLatlng
});
// add the marker to the list
this.markersArray.push(marker);
// add the marker to the map, which is situated in the gmapPanel
marker.setMap(this.gmapPanel.gmap);

Add prepareMap system method, which is invoked after initializing the map (method calling has been described in initComponent).

Parameters: Ext.ux.GMapPanel gMapPanel, google.maps.Map Code:

var me = this;
// set the current position marker (if the position has been specified in the constructor)
if(!Ext.isEmpty(this.currentPosition) && this.currentPosition!==false){
this.addMarker(this.currentPosition.lat ,this.currentPosition.lng);
this.childObjects.selectBtn.enable();
map.setCenter(new google.maps.LatLng(this.currentPosition.lat , this.currentPosition.lng));
}
// handling click on the map, saving the position, moving the marker to another place
google.maps.event.addListener(map, 'click', function(event) {
   me.removeMarkers();
   me.addMarker(event.latLng.mb , event.latLng.nb);
   me.selectedLatLng = event.latLng;
   me.childObjects.selectBtn.enable();
});

The list of methods:

Add the footer toolbar. Place the toolbar -> Panel component to the dockeditems and name it buttonsBar; add the following properties:

  • dock: bottom (locating the toolbar in the bottom)
  • ui: footer (additional button settings)

Add the button selecting the current position.

Place the toolbar-> Fill component as a child element of the buttonsBar and name it bBarFill.

Place the Button component as a child element of the buttonsBar and name it selectBtn.

Set the following button properties: disabled:true (disabled by default)

Add text to the button. This time use another new platform feature.- indicate Javascript instead of assigning text values Thus, instead of “Apply”, write the following: [js:] appLang.APPLY.

The text will display on the button as per the localization settings (dictionaries may be reviewed in the system/lang/ [en.php / ru.php] directory). So, it is easy to create localized versions of the Layout Designer projects.

Add event handler for the click on the selection button.

To do so, open the Events tab on the panel properties panel and add the click handler:

if(this.selectedLatLng!==false){
   this.fireEvent('locationSelected', {
      lat:this.selectedLatLng.mb,
      lng:this.selectedLatLng.nb
    });
}
this.close();

This code checks if any coordinates have been selected. If they have, throw the 'locationSelected' event and pass the coordinates of the last selected point. The event will be described below.

Once the button handler is added, declare the ‘locationSelected’ event so that listeners can be added to it. This is another new system opportunity - creating your own events for extended components.

Open the mapWindow properties and switch to the Events tab. Click “Add Event” and indicate ‘location selected’ in the name field. As we don’t need an event handler, just close the Edit event window at the end.

The Map component has been created. Save and close the project.

Connecting Component to the Project

Connect the component to the user manager. To do so, open the geouser.designer.dat project and connect the component to it (Project config -> Add project file) map.designer.dat

Make sure the embedded project has been successfully connected - click the Related project items button, which opens the list of connected subproject components and their structure.

Now, update the user management window so that coordinates can be inserted from the Map Component. First of all, indicate readOnly:true property for the editWindow_latitude and editWindow_longitude fields.

Add Form Field ->Field Container component to editWindow_generalTab, name it locationContainer and specify the layout: hbox property.

Add another Field Container to locationContainer and name it cordsContainer.

Move the editWindow_latitude and editWindow_longitude fields to the container (cordsContainer).

Add Button to editWindow_generalTab, name it setLocationBtn and set the text: Set location property.

You should get the following component structure in the result:

If you choose editWindow and click show window, you’ll see the following:

All that remains is to define the action to the click event for setLocationBtn button.

Go to Events tab on the setLocationBtn properties panel and find and edit the event in question:

// get link to app.EditWindow.getForm() form
// invoking  getForm() for the second time returns Ext.form.Basic
var form = this.getForm().getForm();
// get coordinate values from the form fields
var lat = form.findField('latitude').getValue();
var lng = form.findField('longitude').getValue();

// if the coordinates are specified, define the marker position on the map
var curPosition = false;
if(lat!==0 && lng!==0){
   curPosition = {'lat':lat,'lng':lng};
}
// create the component item, pass the settings
// add 'locationSelected' event listener, which will fill the form with new values
 
Ext.create('appMapClasses.mapWindow',{
    currentPosition:curPosition,
    listeners:{
        'locationSelected':function(cords){
                 form.findField('latitude').setValue(cords.lat);                                    
                 form.findField('longitude').setValue(cords.lng);
         }
   }
}).show();

Save and close the project, go to the geouser module and see the result: