Felix Kling

Felix Kling

1560866109

Add emoji, GIFs and rich link previews to an Angular 7 chatroom

In this tutorial, you’ll learn three common features of Angular 7 chat chatroom and described how they can be implemented in a Chatkit powered application.

Sometimes, sending only text just isn’t quite enough. This is where the ability to spice up a conversation with GIFs and emoji becomes invaluable. We can provide a richer user experience by adding the ability to search for and select emoji and animated GIFs directly in the chatroom.

An added feature we’ll be looking at in this tutorial is allowing users see what’s behind a link shared in the chatroom without clicking on it using rich link previews. This gives the user more information about a link so they can decide whether to click through or not. In the sections below, I’ll show you how to build out all these features into your Chatkit powered app.

Project setup

This tutorial is a continuation of the How to build a Chatroom with Angular 7 and Chatkit one, so you need to complete that first before moving on to this one. You can clone this GitHub repository and follow the instructions in the README file to get set up.

Prerequisites

  • Basic understanding of Angular and Node.js
  • Node.js (version 8 or later) and npm. Installation instructions are here.

Install additional dependencies

Run the command below from the client directory to install all the additional dependencies we’ll be needing in the course of building this application:

    npm install giphy-api skeleton-css @ctrl/ngx-emoji-mart angular-feather -S


Update the application styles

I made some changes to the CSS to account for the new features we’ll be building, so open up app.component.css and update the styles as follows:

    // client/src/app/app.component.css

    html {
      box-sizing: border-box;
    }

    *, *::before, *::after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
    }

    .App {
      width: 100vw;
      height: 100vh;
      display: flex;
      overflow: hidden;
    }

    ul {
      list-style: none;
    }

    .sidebar {
      flex-basis: 20%;
      background-color: #300d4f;
      color: #fff;
      padding: 5px 10px;
    }

    .sidebar input {
      color: #333;
    }

    .sidebar section {
      margin-bottom: 20px;
    }

    .sidebar h2 {
      margin-bottom: 10px;
    }

    .user-list li {
      margin-bottom: 10px;
      font-size: 16px;
      display: flex;
      align-items: center;
    }

    .presence {
      display: inline-block;
      width: 20px;
      height: 20px;
      background-color: #fff;
      margin-right: 10px;
      border-radius: 50%;
    }

    .presence.online {
      background-color: green;
    }

    .chat-window {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      position: relative;
    }

    .chat-window > * {
      padding: 10px 20px;
    }

    .chat-header, .chat-footer {
      display: flex;
      align-items: center;
    }

    .chat-header {
      border-bottom: 1px solid #ccc;
    }

    .chat-session {
      height: calc(100vh - 108px);
      overflow-y: auto;
      position: relative;
    }

    .message-list {
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
    }

    .user-message {
      margin-top: 10px;
    }

    .user-message span {
      display: block;
    }

    .user-id {
      font-weight: bold;
      margin-bottom: 3px;
    }

    .chat-footer {
      border-top: 1px solid #ccc;
    }

    .chat-footer form, .chat-footer input {
      width: 100%;
    }

    .chat-footer {
      padding: 0 !important;
    }

    .chat-footer form {
      display: flex;
      align-items: center;
      width: 100%;
    }

    .chat-footer input {
      height: 50px;
      flex-grow: 1;
      line-height: 35px;
      padding-left: 20px;
      border-radius: 0;
      border-top-left-radius: 0;
      border-top-right-radius: 0;
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
      border: none;
      font-size: 16px;
      color: #333;
      min-height: auto;
      overflow-y: hidden;
      resize: none;
      border-left: 1px solid #ccc;
    }

    .emoji-mart {
      position: fixed;
      bottom: 70px;
      right: 20px;
    }

    .chat-footer button {
      border: none;
      width: 50px;
      height: auto;
      padding: 0;
      margin-bottom: 0;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .toggle-emoji svg {
      width: 28px;
      height: 28px;
    }

    .giphy-search {
      position: fixed;
      bottom: 70px;
      right: 20px;
      width: 300px;
      height: 300px;
      overflow-y: auto;
      border: 1px solid #ccc;
      border-radius: 4px;
      background-color: #fff;
    }

    .giphy-search input {
      width: 100%;
    }

    img {
      max-width: 100%;
    }

    .gif-result img {
      cursor: pointer;
    }

Next, we need to tell the Angular CLI of some of the other styles our application needs. These styles are from the dependencies we just installed. Open up angular.json and change the styles property as shown below. By doing this, you’re specifying that the referenced styles be included in your application bundle.

    // client/angular.json

    "styles": [
      "src/styles.css",
      "node_modules/@ctrl/ngx-emoji-mart/picker.css",
      "node_modules/skeleton-css/css/skeleton.css",
      "node_modules/skeleton-css/css/normalize.css"
    ]

Start the application

If you haven’t already, install angular-cli globally by running npm install -g @angular/cli in the terminal, then cd to your client directory and run ng serve to build and serve the app at http://localhost:4200. Don’t forget to start your Node.js server by running node server.js from the project root.

Set up the app icons

We’ll be making use of Feather Icons for our iconography needs via the angular-feather package. Before we can use it in our template files, a couple of additional steps are needed.

First, run the command below from the client directory to generate a module to host the icons we’ll import:

    ng generate module icons


The command above should create a new icons.module.ts file in client/src/app/icons/icons.module.ts. Open up the file, and change it to look like this:

    // client/src/app/icons/icons.module.ts

    import { NgModule } from '@angular/core';
    import { IconSmile } from 'angular-feather';

    const icons = [
      IconSmile,
    ];

    @NgModule({
      exports: icons
    })
    export class IconsModule { }

We’re making use of the smile icon in the emoji picker toggle, so we’ve imported it above. Finally, we need to import IconsModule in our app.module.ts and declare it in the imports array as shown below.

    // client/src/app/app.module.ts

    // [..]
    import { IconsModule } from './icons/icons.module';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Now, we’ll be able to use the smile icon in our templates like this <i-smile></i-smile> as you’ll see in the next section.

Add an emoji picker to the room

It is important to provide easy access to emojis in a chat app, and the accepted way of doing so is using an emoji picker where users can easily search for and add an emoji to their message. We’ll be making use of the emoji-mart package to build this feature into our app. Although originally built for React apps, this package has been ported for use in Angular applications as well.

First, let’s add a button that can be used to toggle the emoji picker. Open up app.component.html and change it to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <button
              type="button"
              class="toggle-emoji"
              (click)="toggleEmojiPicker()"
              >
              <i-smile></i-smile>
            </button>
            <input placeholder="Type a message. Hit Enter to send" type="text"
            name="message" [(ngModel)]="message">
          </form>
        </footer>
      </main>
    </div>

Next, update the app.component.ts as follows:

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]
      showEmojiPicker = false;

      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]
    }

The app should look like this now, and the button will toggle the showEmojiPicker flag to true or false when clicked via the toggleEmojiPicker() method.

The next step is to toggle the visibility of the emoji picker based on the value of showEmojiPicker. To use the emoji picker, we need to import the PickerModule in app.module.ts and declare it in the imports array:

    // client/src/app/app.module.ts

    // [..]
    import { PickerModule } from '@ctrl/ngx-emoji-mart';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
        PickerModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Then use the emoji mart component in app.component.html:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <!-- [..] -->

          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
        </section>

      </main>
    </div>

Now, you should be able to toggle the emoji picker by clicking the smile icon.

The next step is make it possible to add an emoji to a message by selecting it in the emoji picker. Notice the (emojiSelect) event on the emoji mart component in app.component.html. It is triggered when an emoji is selected in the picker, and details about the event is passed to the addEmoji() method which updates the message input with the selected emoji.

Create the addEmoji() method in app.component.ts below toggleEmojiPicker():

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      addEmoji(event) {
        const { message } = this;
        const text = `${message}${event.emoji.native}`;

        this.message = text;
        this.showEmojiPicker = false;
      }

      // [..]
    }

You can try it out by selecting an emoji from the emoji picker. It should work as shown below:

Add rich link previews with Microlink

The next feature we’ll add to this app is the ability to show a preview of web content like articles, pages, and YouTube videos shared in the application. We’ll be achieving this using the Microlink package which can be used as an npm package or linked via a CDN.

As I didn’t have much success with getting the npm package to compile, we’ll make use of the provided CDN for this tutorial. Reference the microlink script in client/src/index.html as shown below:

    <!-- client/src/index.html -->

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>AngularChatroom</title>
      <base href="/">

      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>

      <script src="//cdn.jsdelivr.net/npm/@microlink/vanilla@latest/umd/microlink.min.js"></script>
    </body>
    </html>

Following that, we need to detect the presence of a URL in a message and display the link appropriately in the rendered message. To do so, we’ll update the onMessage hook in addUser() as follows:

    // client/src/app/app.component.ts

    hooks: {
      onMessage: message => {
        let { text } = message;
        const urlMatches = message.text.match(/\b(http|https)?:\/\/\S+/gi) || [];

        function insertTextAtIndices(text, obj) {
          return text.replace(/./g, function(character, index) {
            return obj[index] ? obj[index] + character : character;
          });
        }

        urlMatches.forEach(link => {
          const startIndex = text.indexOf(link);
          const endIndex = startIndex + link.length;
          text = insertTextAtIndices(text, {
            [startIndex]: `<a href="${link}" target="_blank" rel="noopener noreferrer" class="embedded-link">`,
            [endIndex]: '</a>',
          });
        });

        this.messages.push({ ...message, text, url_matches: urlMatches, });
      },
      // [..]
    }

Here, we’re matching the message text against a regular expressions and returning an array of URLs found in the message text or an empty array if no links are present in the message. Next, each URL in the array is wrapped in an anchor tag with the help of the insertTextAtIndices() function. Finally, the array of URLs found in the message text are placed in the url_matches property of the message object.

Next, let’s render an anchor tag for each link present in the url_matches and give it a class of .link-preview so that we can target those anchor tags and replace them with rich link previews using microlink. Update app.component.html as follows:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>

        </section>
        <!-- [..] -->
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]

    }

At this point, you be able to view a minimal preview for each link shared in the chatroom.

Share GIFs in the chatroom with Giphy

The final feature for this tutorial involves building out the ability to search for and share GIFs right from within the chat app. We’ll be making use of the Giphy API via the giphy-api package which has already be installed as a dependency.

The user will be able to toggle a GIF picker, search for a GIF by entering a search term, and view the results in the picker. Once a GIF is clicked, it will be sent to the room as an image attachment and rendered on the screen.

Update your app.component.html file to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">q
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <img *ngIf="message.attachment"
                class="image-attachment"
                src="{{ message.attachment.link }}"
                alt="{{ message.attachment.name }}"
                />
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
          <div *ngIf="showGiphySearch" class="giphy-search">
            <form (ngSubmit)="searchGiphy()">
              <input type="text" placeholder="Search for a GIF" name="giphy" [(ngModel)]="giphySearchTerm">
            </form>
            <ul class="search-results">
              <li class="gif-result" *ngFor="let result of giphyResults">
                <img src="{{ result.images.downsized_large.url }}"
                     (click)="sendGif(result.title, result.images.original.url)">
              </li>
            </ul>
          </div>
        </section>
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <!-- [..] -->
            <button type="button" class="toggle-giphy"
              (click)="toggleGiphySearch()">GIF</button>
          </form>
        </footer>
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    import Giphy from 'giphy-api';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]
      showGiphySearch = false;
      giphySearchTerm = '';
      giphyResults = [];

      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      searchGiphy() {
        const giphy = Giphy();
        const searchTerm = this.giphySearchTerm;
        giphy.search(searchTerm)
          .then(res => {
            console.log(res);
            this.giphyResults = res.data;
          })
          .catch(console.error);
      }

      sendGif(title, url) {
        const { currentUser } = this;
        currentUser.sendMessage({
          text: title,
          roomId: '<your room id>',
          attachment: {
            link: url,
            type: 'image',
          }
        }).catch(console.error);
        this.showGiphySearch = false;
      }

      toggleGiphySearch() {
        this.showGiphySearch = !this.showGiphySearch;
      }

      // [..]
    }

The GIF button toggles the visibility of the GIF picker via the toggleGiphySearch() method. Once the user enters a search term and submits the form, the searchGiphy() method is triggered and the results are stored in giphyResults which renders them in the .search-results list. The user can scroll through the list and select their preferred GIF. By clicking on the image, the sendGif() method is triggered, and the animated GIF is rendered in the chat for all the participants.

Here’s a GIF of what the above steps look like in practice. Before you test this out, make sure to replace <your room id> with the appropriate value from your Chatkit instance dashboard.

Wrap up

In this tutorial, I’ve explored three common features of chat applications and described how they can be implemented in a Chatkit powered application. First, we added an emoji picker so that users can quickly search for and include an emoji in their message. Next, we provided rich link previews for links shared in the chatroom, and finally, we added an option to search a library of animated GIFs and share them in the chatroom.

The source code for this project can be found here.

#angular #image

What is GEEK

Buddha Community

Add emoji, GIFs and rich link previews to an Angular 7 chatroom
Lawrence  Lesch

Lawrence Lesch

1678870808

React-codemirror: CodeMirror 6 component for React

React-codemirror

CodeMirror component for React. Demo Preview: @uiwjs.github.io/react-codemirror

Features:

🚀 Quickly and easily configure the API.
🌱 Versions after @uiw/react-codemirror@v4 use codemirror 6. #88.
⚛️ Support the features of React Hook(requires React 16.8+).
📚 Use Typescript to write, better code hints.
🌐 The bundled version supports use directly in the browser #267.
🌎 There are better sample previews.
🎨 Support theme customization, provide theme editor.

Install

Not dependent on uiw.

npm install @uiw/react-codemirror --save

Usage

Open in CodeSandbox

import React from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';

function App() {
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log('value:', value);
  }, []);
  return (
    <CodeMirror
      value="console.log('hello world!');"
      height="200px"
      extensions={[javascript({ jsx: true })]}
      onChange={onChange}
    />
  );
}
export default App;

Support Language

Open in CodeSandbox

import CodeMirror from '@uiw/react-codemirror';
import { StreamLanguage } from '@codemirror/language';
import { go } from '@codemirror/legacy-modes/mode/go';

const goLang = `package main
import "fmt"

func main() {
  fmt.Println("Hello, 世界")
}`;

export default function App() {
  return <CodeMirror value={goLang} height="200px" extensions={[StreamLanguage.define(go)]} />;
}

Markdown Example

Markdown language code is automatically highlighted.

Open in CodeSandbox

import CodeMirror from '@uiw/react-codemirror';
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
import { languages } from '@codemirror/language-data';

const code = `## Title

\`\`\`jsx
function Demo() {
  return <div>demo</div>
}
\`\`\`

\`\`\`bash
# Not dependent on uiw.
npm install @codemirror/lang-markdown --save
npm install @codemirror/language-data --save
\`\`\`

[weisit ulr](https://uiwjs.github.io/react-codemirror/)

\`\`\`go
package main
import "fmt"
func main() {
  fmt.Println("Hello, 世界")
}
\`\`\`
`;

export default function App() {
  return <CodeMirror value={code} extensions={[markdown({ base: markdownLanguage, codeLanguages: languages })]} />;
}

Support Hook

Open in CodeSandbox

import { useEffect, useMemo, useRef } from 'react';
import { useCodeMirror } from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';

const code = "console.log('hello world!');\n\n\n";
// Define the extensions outside the component for the best performance.
// If you need dynamic extensions, use React.useMemo to minimize reference changes
// which cause costly re-renders.
const extensions = [javascript()];

export default function App() {
  const editor = useRef();
  const { setContainer } = useCodeMirror({
    container: editor.current,
    extensions,
    value: code,
  });

  useEffect(() => {
    if (editor.current) {
      setContainer(editor.current);
    }
  }, [editor.current]);

  return <div ref={editor} />;
}

Using Theme

We have created a theme editor where you can define your own theme. We have also defined some themes ourselves, which can be installed and used directly. Below is a usage example:

import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { okaidia } from '@uiw/codemirror-theme-okaidia';

const extensions = [javascript({ jsx: true })];

export default function App() {
  return (
    <CodeMirror
      value="console.log('hello world!');"
      height="200px"
      theme={okaidia}
      extensions={[javascript({ jsx: true })]}
    />
  );
}

Using custom theme

import CodeMirror from '@uiw/react-codemirror';
import { createTheme } from '@uiw/codemirror-themes';
import { javascript } from '@codemirror/lang-javascript';
import { tags as t } from '@lezer/highlight';

const myTheme = createTheme({
  theme: 'light',
  settings: {
    background: '#ffffff',
    foreground: '#75baff',
    caret: '#5d00ff',
    selection: '#036dd626',
    selectionMatch: '#036dd626',
    lineHighlight: '#8a91991a',
    gutterBackground: '#fff',
    gutterForeground: '#8a919966',
  },
  styles: [
    { tag: t.comment, color: '#787b8099' },
    { tag: t.variableName, color: '#0080ff' },
    { tag: [t.string, t.special(t.brace)], color: '#5c6166' },
    { tag: t.number, color: '#5c6166' },
    { tag: t.bool, color: '#5c6166' },
    { tag: t.null, color: '#5c6166' },
    { tag: t.keyword, color: '#5c6166' },
    { tag: t.operator, color: '#5c6166' },
    { tag: t.className, color: '#5c6166' },
    { tag: t.definition(t.typeName), color: '#5c6166' },
    { tag: t.typeName, color: '#5c6166' },
    { tag: t.angleBracket, color: '#5c6166' },
    { tag: t.tagName, color: '#5c6166' },
    { tag: t.attributeName, color: '#5c6166' },
  ],
});
const extensions = [javascript({ jsx: true })];

export default function App() {
  const onChange = React.useCallback((value, viewUpdate) => {
    console.log('value:', value);
  }, []);
  return (
    <CodeMirror
      value="console.log('hello world!');"
      height="200px"
      theme={myTheme}
      extensions={extensions}
      onChange={onChange}
    />
  );
}

Use initialState to restore state from JSON-serialized representation

CodeMirror allows to serialize editor state to JSON representation with toJSON function for persistency or other needs. This JSON representation can be later used to recreate ReactCodeMirror component with the same internal state.

For example, this is how undo history can be saved in the local storage, so that it remains after the page reloads

import CodeMirror from '@uiw/react-codemirror';
import { historyField } from '@codemirror/commands';

// When custom fields should be serialized, you can pass them in as an object mapping property names to fields.
// See [toJSON](https://codemirror.net/docs/ref/#state.EditorState.toJSON) documentation for more details
const stateFields = { history: historyField };

export function EditorWithInitialState() {
  const serializedState = localStorage.getItem('myEditorState');
  const value = localStorage.getItem('myValue') || '';

  return (
    <CodeMirror
      value={value}
      initialState={
        serializedState
          ? {
              json: JSON.parse(serializedState || ''),
              fields: stateFields,
            }
          : undefined
      }
      onChange={(value, viewUpdate) => {
        localStorage.setItem('myValue', value);

        const state = viewUpdate.state.toJSON(stateFields);
        localStorage.setItem('myEditorState', JSON.stringify(state));
      }}
    />
  );
}

Props

  • value?: string value of the auto created model in the editor.
  • width?: string width of editor. Defaults to auto.
  • height?: string height of editor. Defaults to auto.
  • theme?: 'light' / 'dark' / Extension Defaults to 'light'.
import React from 'react';
import { EditorState, EditorStateConfig, Extension } from '@codemirror/state';
import { EditorView, ViewUpdate } from '@codemirror/view';
export * from '@codemirror/view';
export * from '@codemirror/basic-setup';
export * from '@codemirror/state';
export interface UseCodeMirror extends ReactCodeMirrorProps {
  container?: HTMLDivElement | null;
}
export declare function useCodeMirror(props: UseCodeMirror): {
  state: EditorState | undefined;
  setState: import('react').Dispatch<import('react').SetStateAction<EditorState | undefined>>;
  view: EditorView | undefined;
  setView: import('react').Dispatch<import('react').SetStateAction<EditorView | undefined>>;
  container: HTMLDivElement | null | undefined;
  setContainer: import('react').Dispatch<import('react').SetStateAction<HTMLDivElement | null | undefined>>;
};
export interface ReactCodeMirrorProps
  extends Omit<EditorStateConfig, 'doc' | 'extensions'>,
    Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'placeholder'> {
  /** value of the auto created model in the editor. */
  value?: string;
  height?: string;
  minHeight?: string;
  maxHeight?: string;
  width?: string;
  minWidth?: string;
  maxWidth?: string;
  /** focus on the editor. */
  autoFocus?: boolean;
  /** Enables a placeholder—a piece of example content to show when the editor is empty. */
  placeholder?: string | HTMLElement;
  /**
   * `light` / `dark` / `Extension` Defaults to `light`.
   * @default light
   */
  theme?: 'light' | 'dark' | Extension;
  /**
   * Whether to optional basicSetup by default
   * @default true
   */
  basicSetup?: boolean | BasicSetupOptions;
  /**
   * This disables editing of the editor content by the user.
   * @default true
   */
  editable?: boolean;
  /**
   * This disables editing of the editor content by the user.
   * @default false
   */
  readOnly?: boolean;
  /**
   * Whether to optional basicSetup by default
   * @default true
   */
  indentWithTab?: boolean;
  /** Fired whenever a change occurs to the document. */
  onChange?(value: string, viewUpdate: ViewUpdate): void;
  /** Some data on the statistics editor. */
  onStatistics?(data: Statistics): void;
  /** The first time the editor executes the event. */
  onCreateEditor?(view: EditorView, state: EditorState): void;
  /** Fired whenever any state change occurs within the editor, including non-document changes like lint results. */
  onUpdate?(viewUpdate: ViewUpdate): void;
  /**
   * Extension values can be [provided](https://codemirror.net/6/docs/ref/#state.EditorStateConfig.extensions) when creating a state to attach various kinds of configuration and behavior information.
   * They can either be built-in extension-providing objects,
   * such as [state fields](https://codemirror.net/6/docs/ref/#state.StateField) or [facet providers](https://codemirror.net/6/docs/ref/#state.Facet.of),
   * or objects with an extension in its `extension` property. Extensions can be nested in arrays arbitrarily deep—they will be flattened when processed.
   */
  extensions?: Extension[];
  /**
   * If the view is going to be mounted in a shadow root or document other than the one held by the global variable document (the default), you should pass it here.
   * Originally from the [config of EditorView](https://codemirror.net/6/docs/ref/#view.EditorView.constructor%5Econfig.root)
   */
  root?: ShadowRoot | Document;
  /**
   * Create a state from its JSON representation serialized with [toJSON](https://codemirror.net/docs/ref/#state.EditorState.toJSON) function
   */
  initialState?: {
    json: any;
    fields?: Record<'string', StateField<any>>;
  };
}
export interface ReactCodeMirrorRef {
  editor?: HTMLDivElement | null;
  state?: EditorState;
  view?: EditorView;
}
declare const ReactCodeMirror: React.ForwardRefExoticComponent<
  ReactCodeMirrorProps & React.RefAttributes<ReactCodeMirrorRef>
>;
export default ReactCodeMirror;
export interface BasicSetupOptions {
  lineNumbers?: boolean;
  highlightActiveLineGutter?: boolean;
  highlightSpecialChars?: boolean;
  history?: boolean;
  foldGutter?: boolean;
  drawSelection?: boolean;
  dropCursor?: boolean;
  allowMultipleSelections?: boolean;
  indentOnInput?: boolean;
  syntaxHighlighting?: boolean;
  bracketMatching?: boolean;
  closeBrackets?: boolean;
  autocompletion?: boolean;
  rectangularSelection?: boolean;
  crosshairCursor?: boolean;
  highlightActiveLine?: boolean;
  highlightSelectionMatches?: boolean;
  closeBracketsKeymap?: boolean;
  defaultKeymap?: boolean;
  searchKeymap?: boolean;
  historyKeymap?: boolean;
  foldKeymap?: boolean;
  completionKeymap?: boolean;
  lintKeymap?: boolean;
}
import { EditorSelection, SelectionRange } from '@codemirror/state';
import { ViewUpdate } from '@codemirror/view';
export interface Statistics {
  /** Get the number of lines in the editor. */
  lineCount: number;
  /** total length of the document */
  length: number;
  /** Get the proper [line-break](https://codemirror.net/docs/ref/#state.EditorState^lineSeparator) string for this state. */
  lineBreak: string;
  /** Returns true when the editor is [configured](https://codemirror.net/6/docs/ref/#state.EditorState^readOnly) to be read-only. */
  readOnly: boolean;
  /** The size (in columns) of a tab in the document, determined by the [`tabSize`](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize) facet. */
  tabSize: number;
  /** Cursor Position */
  selection: EditorSelection;
  /** Make sure the selection only has one range. */
  selectionAsSingle: SelectionRange;
  /** Retrieves a list of all current selections. */
  ranges: readonly SelectionRange[];
  /** Get the currently selected code. */
  selectionCode: string;
  /**
   * The length of the given array should be the same as the number of active selections.
   * Replaces the content of the selections with the strings in the array.
   */
  selections: string[];
  /** Return true if any text is selected. */
  selectedText: boolean;
}
export declare const getStatistics: (view: ViewUpdate) => Statistics;

All Packages

NameNPM VersionWebsite
@uiw/react-codemirrornpm version NPM Downloads#preview
@uiw/codemirror-extensions-basic-setupnpm version NPM Downloads#preview
@uiw/codemirror-extensions-colornpm version NPM Downloads#preview
@uiw/codemirror-extensions-classnamenpm version NPM Downloads#preview
@uiw/codemirror-extensions-eventsnpm version NPM Downloads#preview
@uiw/codemirror-extensions-hyper-linknpm version NPM Downloads#preview
@uiw/codemirror-extensions-langsnpm version NPM Downloads#preview
@uiw/codemirror-extensions-line-numbers-relativenpm version NPM Downloads#preview
@uiw/codemirror-extensions-mentionsnpm version NPM Downloads#preview
@uiw/codemirror-extensions-zebra-stripesnpm version NPM Downloads#preview
@uiw/codemirror-themesnpm version NPM Downloads#preview
NameNPM VersionWebsite
@uiw/codemirror-themes-allnpm version NPM Downloads#preview
@uiw/codemirror-theme-abcdefnpm version NPM Downloads#preview
@uiw/codemirror-theme-androidstudionpm version NPM Downloads#preview
@uiw/codemirror-theme-atomonenpm version NPM Downloads#preview
@uiw/codemirror-theme-auranpm version NPM Downloads#preview
@uiw/codemirror-theme-bbeditnpm version NPM Downloads#preview
@uiw/codemirror-theme-bespinnpm version NPM Downloads#preview
@uiw/codemirror-theme-duotonenpm version NPM Downloads#preview
@uiw/codemirror-theme-draculanpm version NPM Downloads#preview
@uiw/codemirror-theme-darculanpm version NPM Downloads#preview
@uiw/codemirror-theme-eclipsenpm version NPM Downloads#preview
@uiw/codemirror-theme-githubnpm version NPM Downloads#preview
@uiw/codemirror-theme-gruvbox-darknpm version NPM Downloads#preview
@uiw/codemirror-theme-materialnpm version NPM Downloads#preview
@uiw/codemirror-theme-noctis-lilacnpm version NPM Downloads#preview
@uiw/codemirror-theme-nordnpm version NPM Downloads#preview
@uiw/codemirror-theme-okaidianpm version NPM Downloads#preview
@uiw/codemirror-theme-solarizednpm version NPM Downloads#preview
@uiw/codemirror-theme-sublimenpm version NPM Downloads#preview
@uiw/codemirror-theme-tokyo-nightnpm version NPM Downloads#preview
@uiw/codemirror-theme-tokyo-night-stormnpm version NPM Downloads#preview
@uiw/codemirror-theme-tokyo-night-daynpm version NPM Downloads#preview
@uiw/codemirror-theme-vscodenpm version NPM Downloads#preview
@uiw/codemirror-theme-xcodenpm version NPM Downloads#preview

Related


Download Details:

Author: uiwjs
Source Code: https://github.com/uiwjs/react-codemirror 
License: MIT license

#typescript #react #editor #hook #codemirror 

Jack Salvator

Jack Salvator

1608113009

New Angular 7 Features With Example - Info Stans

What is new in New Angular 7? New Angular 7 features have turned out as a powerful release that really brought advancement in the application development structure.

Here, we have listed new Angular 7 features with examples and write the difference between Angular 6 and Angular 7.

  • Bundle Budget
  • Virtual Scrolling
  • Error Handling
  • Documentation Updates
  • Application Performance
  • Native Script
  • CLI Prompts
  • Component in angular 7
  • Drag and Drop
  • Angular Do-Bootstrap

Read more: Angular 7 Features With Example

#angular 7 features #what’s new angular 7 #new angular 7 features #angular 7 features with examples

Felix Kling

Felix Kling

1560866109

Add emoji, GIFs and rich link previews to an Angular 7 chatroom

In this tutorial, you’ll learn three common features of Angular 7 chat chatroom and described how they can be implemented in a Chatkit powered application.

Sometimes, sending only text just isn’t quite enough. This is where the ability to spice up a conversation with GIFs and emoji becomes invaluable. We can provide a richer user experience by adding the ability to search for and select emoji and animated GIFs directly in the chatroom.

An added feature we’ll be looking at in this tutorial is allowing users see what’s behind a link shared in the chatroom without clicking on it using rich link previews. This gives the user more information about a link so they can decide whether to click through or not. In the sections below, I’ll show you how to build out all these features into your Chatkit powered app.

Project setup

This tutorial is a continuation of the How to build a Chatroom with Angular 7 and Chatkit one, so you need to complete that first before moving on to this one. You can clone this GitHub repository and follow the instructions in the README file to get set up.

Prerequisites

  • Basic understanding of Angular and Node.js
  • Node.js (version 8 or later) and npm. Installation instructions are here.

Install additional dependencies

Run the command below from the client directory to install all the additional dependencies we’ll be needing in the course of building this application:

    npm install giphy-api skeleton-css @ctrl/ngx-emoji-mart angular-feather -S


Update the application styles

I made some changes to the CSS to account for the new features we’ll be building, so open up app.component.css and update the styles as follows:

    // client/src/app/app.component.css

    html {
      box-sizing: border-box;
    }

    *, *::before, *::after {
      box-sizing: inherit;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
    }

    .App {
      width: 100vw;
      height: 100vh;
      display: flex;
      overflow: hidden;
    }

    ul {
      list-style: none;
    }

    .sidebar {
      flex-basis: 20%;
      background-color: #300d4f;
      color: #fff;
      padding: 5px 10px;
    }

    .sidebar input {
      color: #333;
    }

    .sidebar section {
      margin-bottom: 20px;
    }

    .sidebar h2 {
      margin-bottom: 10px;
    }

    .user-list li {
      margin-bottom: 10px;
      font-size: 16px;
      display: flex;
      align-items: center;
    }

    .presence {
      display: inline-block;
      width: 20px;
      height: 20px;
      background-color: #fff;
      margin-right: 10px;
      border-radius: 50%;
    }

    .presence.online {
      background-color: green;
    }

    .chat-window {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      position: relative;
    }

    .chat-window > * {
      padding: 10px 20px;
    }

    .chat-header, .chat-footer {
      display: flex;
      align-items: center;
    }

    .chat-header {
      border-bottom: 1px solid #ccc;
    }

    .chat-session {
      height: calc(100vh - 108px);
      overflow-y: auto;
      position: relative;
    }

    .message-list {
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
    }

    .user-message {
      margin-top: 10px;
    }

    .user-message span {
      display: block;
    }

    .user-id {
      font-weight: bold;
      margin-bottom: 3px;
    }

    .chat-footer {
      border-top: 1px solid #ccc;
    }

    .chat-footer form, .chat-footer input {
      width: 100%;
    }

    .chat-footer {
      padding: 0 !important;
    }

    .chat-footer form {
      display: flex;
      align-items: center;
      width: 100%;
    }

    .chat-footer input {
      height: 50px;
      flex-grow: 1;
      line-height: 35px;
      padding-left: 20px;
      border-radius: 0;
      border-top-left-radius: 0;
      border-top-right-radius: 0;
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
      border: none;
      font-size: 16px;
      color: #333;
      min-height: auto;
      overflow-y: hidden;
      resize: none;
      border-left: 1px solid #ccc;
    }

    .emoji-mart {
      position: fixed;
      bottom: 70px;
      right: 20px;
    }

    .chat-footer button {
      border: none;
      width: 50px;
      height: auto;
      padding: 0;
      margin-bottom: 0;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .toggle-emoji svg {
      width: 28px;
      height: 28px;
    }

    .giphy-search {
      position: fixed;
      bottom: 70px;
      right: 20px;
      width: 300px;
      height: 300px;
      overflow-y: auto;
      border: 1px solid #ccc;
      border-radius: 4px;
      background-color: #fff;
    }

    .giphy-search input {
      width: 100%;
    }

    img {
      max-width: 100%;
    }

    .gif-result img {
      cursor: pointer;
    }

Next, we need to tell the Angular CLI of some of the other styles our application needs. These styles are from the dependencies we just installed. Open up angular.json and change the styles property as shown below. By doing this, you’re specifying that the referenced styles be included in your application bundle.

    // client/angular.json

    "styles": [
      "src/styles.css",
      "node_modules/@ctrl/ngx-emoji-mart/picker.css",
      "node_modules/skeleton-css/css/skeleton.css",
      "node_modules/skeleton-css/css/normalize.css"
    ]

Start the application

If you haven’t already, install angular-cli globally by running npm install -g @angular/cli in the terminal, then cd to your client directory and run ng serve to build and serve the app at http://localhost:4200. Don’t forget to start your Node.js server by running node server.js from the project root.

Set up the app icons

We’ll be making use of Feather Icons for our iconography needs via the angular-feather package. Before we can use it in our template files, a couple of additional steps are needed.

First, run the command below from the client directory to generate a module to host the icons we’ll import:

    ng generate module icons


The command above should create a new icons.module.ts file in client/src/app/icons/icons.module.ts. Open up the file, and change it to look like this:

    // client/src/app/icons/icons.module.ts

    import { NgModule } from '@angular/core';
    import { IconSmile } from 'angular-feather';

    const icons = [
      IconSmile,
    ];

    @NgModule({
      exports: icons
    })
    export class IconsModule { }

We’re making use of the smile icon in the emoji picker toggle, so we’ve imported it above. Finally, we need to import IconsModule in our app.module.ts and declare it in the imports array as shown below.

    // client/src/app/app.module.ts

    // [..]
    import { IconsModule } from './icons/icons.module';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Now, we’ll be able to use the smile icon in our templates like this <i-smile></i-smile> as you’ll see in the next section.

Add an emoji picker to the room

It is important to provide easy access to emojis in a chat app, and the accepted way of doing so is using an emoji picker where users can easily search for and add an emoji to their message. We’ll be making use of the emoji-mart package to build this feature into our app. Although originally built for React apps, this package has been ported for use in Angular applications as well.

First, let’s add a button that can be used to toggle the emoji picker. Open up app.component.html and change it to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <button
              type="button"
              class="toggle-emoji"
              (click)="toggleEmojiPicker()"
              >
              <i-smile></i-smile>
            </button>
            <input placeholder="Type a message. Hit Enter to send" type="text"
            name="message" [(ngModel)]="message">
          </form>
        </footer>
      </main>
    </div>

Next, update the app.component.ts as follows:

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]
      showEmojiPicker = false;

      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]
    }

The app should look like this now, and the button will toggle the showEmojiPicker flag to true or false when clicked via the toggleEmojiPicker() method.

The next step is to toggle the visibility of the emoji picker based on the value of showEmojiPicker. To use the emoji picker, we need to import the PickerModule in app.module.ts and declare it in the imports array:

    // client/src/app/app.module.ts

    // [..]
    import { PickerModule } from '@ctrl/ngx-emoji-mart';

    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        IconsModule,
        PickerModule,
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }

Then use the emoji mart component in app.component.html:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <!-- [..] -->

          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
        </section>

      </main>
    </div>

Now, you should be able to toggle the emoji picker by clicking the smile icon.

The next step is make it possible to add an emoji to a message by selecting it in the emoji picker. Notice the (emojiSelect) event on the emoji mart component in app.component.html. It is triggered when an emoji is selected in the picker, and details about the event is passed to the addEmoji() method which updates the message input with the selected emoji.

Create the addEmoji() method in app.component.ts below toggleEmojiPicker():

    // client/src/app/app.component.ts

    // [..]
    export class AppComponent {
      // [..]

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      addEmoji(event) {
        const { message } = this;
        const text = `${message}${event.emoji.native}`;

        this.message = text;
        this.showEmojiPicker = false;
      }

      // [..]
    }

You can try it out by selecting an emoji from the emoji picker. It should work as shown below:

Add rich link previews with Microlink

The next feature we’ll add to this app is the ability to show a preview of web content like articles, pages, and YouTube videos shared in the application. We’ll be achieving this using the Microlink package which can be used as an npm package or linked via a CDN.

As I didn’t have much success with getting the npm package to compile, we’ll make use of the provided CDN for this tutorial. Reference the microlink script in client/src/index.html as shown below:

    <!-- client/src/index.html -->

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>AngularChatroom</title>
      <base href="/">

      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>

      <script src="//cdn.jsdelivr.net/npm/@microlink/vanilla@latest/umd/microlink.min.js"></script>
    </body>
    </html>

Following that, we need to detect the presence of a URL in a message and display the link appropriately in the rendered message. To do so, we’ll update the onMessage hook in addUser() as follows:

    // client/src/app/app.component.ts

    hooks: {
      onMessage: message => {
        let { text } = message;
        const urlMatches = message.text.match(/\b(http|https)?:\/\/\S+/gi) || [];

        function insertTextAtIndices(text, obj) {
          return text.replace(/./g, function(character, index) {
            return obj[index] ? obj[index] + character : character;
          });
        }

        urlMatches.forEach(link => {
          const startIndex = text.indexOf(link);
          const endIndex = startIndex + link.length;
          text = insertTextAtIndices(text, {
            [startIndex]: `<a href="${link}" target="_blank" rel="noopener noreferrer" class="embedded-link">`,
            [endIndex]: '</a>',
          });
        });

        this.messages.push({ ...message, text, url_matches: urlMatches, });
      },
      // [..]
    }

Here, we’re matching the message text against a regular expressions and returning an array of URLs found in the message text or an empty array if no links are present in the message. Next, each URL in the array is wrapped in an anchor tag with the help of the insertTextAtIndices() function. Finally, the array of URLs found in the message text are placed in the url_matches property of the message object.

Next, let’s render an anchor tag for each link present in the url_matches and give it a class of .link-preview so that we can target those anchor tags and replace them with rich link previews using microlink. Update app.component.html as follows:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>

        </section>
        <!-- [..] -->
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      toggleEmojiPicker() {
        this.showEmojiPicker = !this.showEmojiPicker;
      }

      // [..]

    }

At this point, you be able to view a minimal preview for each link shared in the chatroom.

Share GIFs in the chatroom with Giphy

The final feature for this tutorial involves building out the ability to search for and share GIFs right from within the chat app. We’ll be making use of the Giphy API via the giphy-api package which has already be installed as a dependency.

The user will be able to toggle a GIF picker, search for a GIF by entering a search term, and view the results in the picker. Once a GIF is clicked, it will be sent to the room as an image attachment and rendered on the screen.

Update your app.component.html file to look like this:

    // client/src/app/app.component.html

    <div class="App">
      <!-- [..] -->

      <main class="chat-window">
        <!-- [..] -->
        <section class="chat-session">
          <ul class="message-list">
            <li class="user-message" *ngFor="let message of messages">q
              <span class="user-id">{{ message.senderId }}</span>
              <span [innerHTML]="message.text"></span>
              <img *ngIf="message.attachment"
                class="image-attachment"
                src="{{ message.attachment.link }}"
                alt="{{ message.attachment.name }}"
                />
              <a *ngFor="let link of message.url_matches" href="{{ link }}"
                class="link-preview">{{
                link }}</a>
            </li>
          </ul>
          <emoji-mart class="emoji-mart" set="emojione" (emojiSelect)="addEmoji($event)" *ngIf="showEmojiPicker" title="Pick your emoji…"></emoji-mart>
          <div *ngIf="showGiphySearch" class="giphy-search">
            <form (ngSubmit)="searchGiphy()">
              <input type="text" placeholder="Search for a GIF" name="giphy" [(ngModel)]="giphySearchTerm">
            </form>
            <ul class="search-results">
              <li class="gif-result" *ngFor="let result of giphyResults">
                <img src="{{ result.images.downsized_large.url }}"
                     (click)="sendGif(result.title, result.images.original.url)">
              </li>
            </ul>
          </div>
        </section>
        <footer class="chat-footer">
          <form (ngSubmit)='sendMessage()'>
            <!-- [..] -->
            <button type="button" class="toggle-giphy"
              (click)="toggleGiphySearch()">GIF</button>
          </form>
        </footer>
      </main>
    </div>

Then update app.component.ts as follows:

    // client/src/app/app.component.ts

    import { Component, AfterViewChecked } from '@angular/core';
    import Chatkit from '@pusher/chatkit-client';
    import axios from 'axios';
    import Giphy from 'giphy-api';
    declare const microlink;

    // [..]

    export class AppComponent implements AfterViewChecked {
      // [..]
      showGiphySearch = false;
      giphySearchTerm = '';
      giphyResults = [];

      // [..]

      ngAfterViewChecked() {
        microlink('.link-preview');
      }

      searchGiphy() {
        const giphy = Giphy();
        const searchTerm = this.giphySearchTerm;
        giphy.search(searchTerm)
          .then(res => {
            console.log(res);
            this.giphyResults = res.data;
          })
          .catch(console.error);
      }

      sendGif(title, url) {
        const { currentUser } = this;
        currentUser.sendMessage({
          text: title,
          roomId: '<your room id>',
          attachment: {
            link: url,
            type: 'image',
          }
        }).catch(console.error);
        this.showGiphySearch = false;
      }

      toggleGiphySearch() {
        this.showGiphySearch = !this.showGiphySearch;
      }

      // [..]
    }

The GIF button toggles the visibility of the GIF picker via the toggleGiphySearch() method. Once the user enters a search term and submits the form, the searchGiphy() method is triggered and the results are stored in giphyResults which renders them in the .search-results list. The user can scroll through the list and select their preferred GIF. By clicking on the image, the sendGif() method is triggered, and the animated GIF is rendered in the chat for all the participants.

Here’s a GIF of what the above steps look like in practice. Before you test this out, make sure to replace <your room id> with the appropriate value from your Chatkit instance dashboard.

Wrap up

In this tutorial, I’ve explored three common features of chat applications and described how they can be implemented in a Chatkit powered application. First, we added an emoji picker so that users can quickly search for and include an emoji in their message. Next, we provided rich link previews for links shared in the chatroom, and finally, we added an option to search a library of animated GIFs and share them in the chatroom.

The source code for this project can be found here.

#angular #image

Christa  Stehr

Christa Stehr

1598940617

Install Angular - Angular Environment Setup Process

Angular is a TypeScript based framework that works in synchronization with HTML, CSS, and JavaScript. To work with angular, domain knowledge of these 3 is required.

  1. Installing Node.js and npm
  2. Installing Angular CLI
  3. Creating workspace
  4. Deploying your First App

In this article, you will get to know about the Angular Environment setup process. After reading this article, you will be able to install, setup, create, and launch your own application in Angular. So let’s start!!!

Angular environment setup

Install Angular in Easy Steps

For Installing Angular on your Machine, there are 2 prerequisites:

  • Node.js
  • npm Package Manager
Node.js

First you need to have Node.js installed as Angular require current, active LTS or maintenance LTS version of Node.js

Download and Install Node.js version suitable for your machine’s operating system.

Npm Package Manager

Angular, Angular CLI and Angular applications are dependent on npm packages. By installing Node.js, you have automatically installed the npm Package manager which will be the base for installing angular in your system. To check the presence of npm client and Angular version check of npm client, run this command:

  1. npm -v

Installing Angular CLI

  • Open Terminal/Command Prompt
  • To install Angular CLI, run the below command:
  1. npm install -g @angular/cli

installing angular CLI

· After executing the command, Angular CLI will get installed within some time. You can check it using the following command

  1. ng --version

Workspace Creation

Now as your Angular CLI is installed, you need to create a workspace to work upon your application. Methods for it are:

  • Using CLI
  • Using Visual Studio Code
1. Using CLI

To create a workspace:

  • Navigate to the desired directory where you want to create your workspace using cd command in the Terminal/Command prompt
  • Then in the directory write this command on your terminal and provide the name of the app which you want to create. In my case I have mentioned DataFlair:
  1. Ng new YourAppName

create angular workspace

  • After running this command, it will prompt you to select from various options about the CSS and other functionalities.

angular CSS options

  • To leave everything to default, simply press the Enter or the Return key.

angular setup

#angular tutorials #angular cli install #angular environment setup #angular version check #download angular #install angular #install angular cli

Clara  Gutmann

Clara Gutmann

1598727360

Angular 8 Updates And Summary of New Features

Angular 8 Updates And Summary of New Features is today’s topic. Angular 8 arrives with an impressive list of changes and improvements including the much-anticipated Ivy compiler as an opt-in feature. You can check out  Angular 7 features and updates if you have not seen yet. In this blog, we have written some articles about  Angular 7 Crud,  Angular 7 Routing,  Angular ngClass,  Angular ngFor.

Angular 8 Updates And Summary

See the following updates.

TypeScript 3.4

Angular 8.0 is now supported TypeScript 3.4, and even requires it, so you will need to upgrade.

You can look at what  TypeScript 3.3 and  TypeScript 3.4 brings on the table on official Microsoft blog.

#angular #typescript #angular 7 crud #angular 7 routing #angular 8