How to add event to some asynchronous content after loaded


#1

Hi everyone, My name is Javier and I am new at ionic.

I am creating an app that gets some descriptions from a webservice. This descriptions (text) includes some words that I want them to be tappable to obtain a definition. Could somebody help me with an idea of how to solve this?

Thanks in advance :relaxed:


#2

How does the data you get look like?
What exactly should happen when you tab that “link”?


#3

First of all, thanks Sujan12 for your fast answer. I am going to provide you more details.

It is bassically plain text, but I have thought to mark the ‘special words’ in an html-link format.
E.g.

Amphibians (Amphis bios: both Bios: life) are <a href="#">tetrapods</a> which, ...

Just to have a way to identify these words, but probably I could choose other way to identify them.

I would like to open a modal page with some short information related to the word tapped and return to this main page after closing the modal page.

I have been researching and trying a lot of stuff, but I didn’t find a solution yet. :sweat:


#4

Ok so you control the web service and can change the output?
Where do you get the “definitions” from?

I suggest you implement the “tooltips” for the definitions locally, with a static text first to get that out of the way. Then you look into how to load the text dynamically and maybe ad the needed markup to make the tooltips work.


#5

Yes! I control the web service and I can change the output. I get the “words information” also from the same web service with other query, but this information could be complex, even including images in some cases. Tooltips could be a good solution for short information. But that is not my case.:confused:
I want to implement this dinamically just because I can have these tappable words in several definitions and if I could assign an event I would call the websrvice to get the specific information showing it in a modal tab. I know that this is a very particular scenario…


#6

Still: First implement something with local, static data before you worry about getting data dynamically. Otherwise you are trying to solve two problems at the same time. If you already conquered the display and interface part, making it dynamic will be much easier.

What do you mean by that exactly? Load on demand?

Don’t worry, just asking so many question to get all the information. To be honest I have no idea how to best do this, but I hope someone else will with this information here now.


#7

Yes

Thank you very much for your interest. You are right in that sometimes I want to do too much at the same time. I am going to simplify my problem and try to find a solution little by little. I will let you know when I get it :grinning: and I am open to receive more advices :slight_smile:.


#8

This is much harder than it would probably appear. Perhaps you can consider adapting this strategy.


#9

This strategy is really helpful for my problem. Thank you so much! :grin:


#10

I finally got the solution! :grinning:

First of all I have defined a Markdown, in my case I have chosen the following format
[link:id](link-text), where id is a number that identifies my ‘special word’

E.g.
Amphibians (Amphis bios: both Bios: life) are [link:1](tetrapods) which, although

Then, in my DataService class, I use regular expressions to extract separately the
plain text, the links id’s and the link text and I include this information in the received object before mapping.

import { Injectable } from '@angular/core'; 
import { Http, Headers } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class DataService { 

  private regExpSplit = /\[link:[0-9]+\]\([a-zñÑáéíóúÁÉÍÓÚüÜ]+\)/ig;
  private regExpMatchLinks = /\[link:([0-9])+\]\(([a-zñÑáéíóúÁÉÍÓÚüÜ]+)\)/ig;

  constructor(private http: Http) { }

  getClassifications(language) {
    return this.http.get('http://webserviceurlwhatever?action=classifications&lan='+language)
               .map(data => this.prepareClassifications(data));
  } 

  private prepareClassifications(data){
    let classifications = JSON.parse(data.text()).classifications;
    for(let i=0; i<classifications.length;i++){
      classifications[i].bones = this.getBones(classifications[i].maincharacteristics);
    }
    return classifications;
  }

  private getBones(textWithLinks: string){
    let textFragments = textWithLinks.split(this.regExpSplit);
    let linkIds = new Array();
    let linkTexts = new Array();
    let foundLinks = new Array();
    let bones = new Array();

    while ((foundLinks = this.regExpMatchLinks.exec(textWithLinks)) !== null) {
      if(foundLinks[1]!=null){
        linkIds.push(foundLinks[1]);
        linkTexts.push(foundLinks[2]);
      }
    }

    for(var i=0;i<textFragments.length;i++){
      let bone = Object();
      bone.text = textFragments[i];
      bone.linkId = linkIds[i] == null ? -1 : linkIds[i];
      bone.linkText = linkTexts[i] == null ? "" : linkTexts[i];
      bones.push(bone);
    }

    return bones;
  }
}

In the controller I have just created a method to obtain the data.

import { Component } from '@angular/core';
import { DataService } from '../../services/data.service';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
  providers: [DataService]
})
export class HomePage {

  public terms;
  public language;

  constructor(private dataservice: DataService, private nav: NavController) {  }

  public getClassifications() {
        this.terms = this.dataservice.getClassifications(this.language);
  }

  public showInfo(id){
    //Just to test that it is working!
    alert("Link " + id);
  }
}

And finally the template in my html file

<ion-header>
  <ion-navbar>
    <ion-title>
      Amphibians &amp; Reptiles
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content paddingio>
  <ion-list inset>
        <ion-item>
            <ion-label>Language</ion-label>
            <ion-input [(ngModel)]="language" type="text"></ion-input>
        </ion-item>
    </ion-list>
    <div padding>
        <button ion-button block (click)="getClassifications()">Search</button>
    </div>
    <ion-card *ngFor="let term of terms | async">
        <ion-card-header>
            {{ term.name }}
        </ion-card-header>
        <ion-card-content>
           <span *ngFor="let bone of term.bones">
             {{ bone.text }}
              <span *ngIf="bone.linkId != -1" style="color:red;font-weight:bold" (click)="showInfo(bone.linkId)">
                {{ bone.linkText }}
              </span>
           </span>
        </ion-card-content>
    </ion-card>
</ion-content>

Of course this code can be refactor :relaxed:, but I was happy and I wanted to share. Maybe could be useful for someone else.

Thank you Sujan12 and rapropos :slight_smile:


#11

I would strongly suggest switching your intermediate format to something more strongly defined and easy to parse, such as JSON.

There’s a saying that goes something like this:

You have a problem, so you write a regular expression to solve it.
Now you have two problems.

Regex-based parsers are devilishly difficult to write. Just when you think you’ve covered all the edge cases, somebody comes along and drops the equivalent of “Little Bobby Tables” into incoming data (such as an unforseen delimiter character).

If you’re interested in pursuing this further, here is another post on this general topic that includes a JSON representation of these heterogeneous bone collections.


#12

It is true that is difficult to build a never-failing regular expression. I know other saying in Spanish (I don’t know if it makes sense in English: ‘Regular expressions are neither good nor bad, just regular.’) But I don’t understand how to apply your example to parse the original text with the link markdown. I understand how the template is defined, based on the json received, but the main problem now is how to parse the text to obtain a json without using regular expressions.


#13

I would suggest that you do as much as you can on the server side. It makes coding easier, and will improve performance. Since you have control over the server, is it possible for you to do preprocessing to create JSON there?


#14

Yes, I can do the processing in the server and read the json with the text and links structured in the app. I will also use other way to represent the information in the server database to avoid using regular expressions. Thanks for your suggestions.


#15

For somebody with admittedly little familiarity with the framework, you have demonstrated some of the most impressive skill and rapid adaptability of any poster I have encountered here. You rock.


#16

Thank you very much! I am really delighted with ionic.I tried before to develop mobile apps with android studio and it was frustrating for me. Ionic is more intuitive and easy to understand, at least for me. There is a lot of useful and free resources, and it is so gratifying to find people like you providing help unselfishly.