Sivvio
Sivvio

Reputation: 297

*ngFor displaying 2 arrays in alternate way in Angular 4

I'm creating a chatbot in angular 4 and I'm struggling a bit on how to display the messages properly. On enter I simply parse the value which is sent for computation, and at the same time stored into an array userMessage. When I get the response from the bot, I store that into another array called botMessage. Assuming I sent 3 messages this is how the output will display:

The output that I want to display is the one of a normal chat so it would be:

This is my html code

  <ul >
    <li class="bubble user-message" *ngFor = "let message of userMessage ">
      {{message}}
    </li>
    <li class ="bubble bot-message" *ngFor = "let message of botMessage">
      {{message}}
    </li>

  </ul>

Any suggestions? Thank you very much

edit this is my typescript code:

inputField

//this is called when enter is pressed. apiCall would be the service
onEnter(value: string) {
    this.value = value;
    this.userMessage.push(value);        
    this.apiCall.postValue(value this.output );
    this.botMessage = this.apiCall.getMessages();
    this.chat.displayMessages();
  } //on enter

this is my service

private messages = [];
postValue(value:string, output:any){
  this.http.post('/APIconversation', {"input":value})
  .map(response=>response.json())
  .subscribe(
      data => {
            // Read the result field from the JSON response.
            output = data.text;                


            this.messages.push(output);
     }
  )
}

getMessages(){
    return this.messages;
}

this is where I parse the arrays to the html to be rendered

@Input() userMessage: InputFieldComponent; //gets the array userMessage from the parent (input-field)   
@Input() botMessage: InputFieldComponent; //gets the array botMessage from the parent (input-field)   

displayMessages() {
    this.messages = this.apiCall.getMessages();   
}

Upvotes: 0

Views: 953

Answers (3)

Markus Kollers
Markus Kollers

Reputation: 3718

updated answer

I recommend to store your bot-messages in an dictionary, with the key of the user-message like this:

botMessage = {};
userMessage = [];

onEnter(value: string) {
    this.userMessage.push(value); 
    var context = this.apiCall.getContext(value); 
    this.apiCall.postValue(value, context, this.output);

    const botMessages = this.apiCall.getMessages();

    // Add all bot messages depending on their user messages
    for(const message of botMessages) {
        this.botMessage[message.userMessageId] = message;
    }
} 

Implied, that your bot-message has the info to which user-message it depends. With this structure, you can easily access the answer in your html like this:

<ul>
  <li class="bubble" *ngFor="let message of userMessage">
      <div class="user-message>{{ message }}</div>
      <div *ngIf="botMessage[message.id]" class="bot-message>
        {{ botMessage[message.id] }}
      </div>
  </li>
</ul>

Also I'm pretty sure, you have some asynchronous problems, but that's another chapter :-)

Upvotes: 2

Juan
Juan

Reputation: 6383

Keeping your data model, you could use an index:

  <ul *ngFor = "let message of userMessage; let i=index;">
    <li>
      {{ message }}
    </li>
    <li> {{ botMessage[i] }} </li>
  </ul>

Then adjust where to place the *ngFor.

The result is the one you would expect.

Link to plunker here

You would though need to check for lengths as they might be different between arrays, I'd recommend evaluating your data model.

Upvotes: 0

Sajeetharan
Sajeetharan

Reputation: 222522

You could merge these arrays into one and use a condition to check the bot and user based on a object property, you can't achieve with two arrays,

  <div *ngFor="let message of Messages"
        <div *ngIf="message.type === 'User'">
                <user-message-item [message]="message"></sender-message-item>
            </div>
            <div *ngIf="message.type === 'Bot'">
                <bot-message-item [message]="message"></receiver-message-item>
            </div>
 </div>

Upvotes: 0

Related Questions