# Adding Non-WebMap Angular Forms

The following section will guide you through this case scenario, in which you would need to add a non-WebMap Angular form to an existing migrated Angular project. This means that the developer can add new forms that don't use the WebMap model paradigm and launch them from the existing WebMap migrated app.

The initial assumption is that the developer already has access to a migrated WebMap Angular project, and the developer already implemented on the project a FrontEnd click handler in a menu item (just like the one described in the existing [post](/webmap/winforms/extend-or-modify-the-converted-application/adding-frontend-handler-to-a-toolstripmenuitem.md) on this site).

The first step is to create an Angular component named **NoWebMapFormsContainerComponent.** This component will be in charge of handling the open and close of the new forms that don't use the WebMap mechanism.

{% tabs %}
{% tab title="no-web-map-forms-container.components.ts" %}

```typescript
/***********************************************************************
 * Copyright (C) Mobilize.Net <info@mobilize.net> - All Rights Reserved
 *
 * This file is part of the Mobilize Frameworks, which is
 * proprietary and confidential.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Mobilize.Net Corporation.
 * The intellectual and technical concepts contained herein are
 * proprietary to Mobilize.Net Corporation and may be covered
 * by U.S. Patents, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Mobilize.Net Corporation.
 *
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE.txt', which is part of this source code package.
 ***********************************************************************/
 import {
  ChangeDetectorRef,
  Component,
  ComponentFactoryResolver,
  ComponentRef,
  OnDestroy,
  OnInit,
  ViewChild,
} from '@angular/core';
import { WebMapService, WMConstants } from '@mobilize/angularclient';
import { WMLogger } from '@mobilize/logging';
import { ContainerDirective } from '@mobilize/base-components';
import { TypeResolver } from '@mobilize/base-components';
import { ErrorCodes, ExceptionHandlerClass } from '@mobilize/webmap-core';

@Component({
  selector: 'wm-nowebmapformscontainer',
  styleUrls: ['./no-web-map-forms-container.component.css'],
  templateUrl: './no-web-map-forms-container.component.html'
})
@ExceptionHandlerClass(ErrorCodes.BaseComponents)
export class NoWebMapFormsContainerComponent implements OnInit, OnDestroy {
  constructor(
    private changeDetector: ChangeDetectorRef,
    private componentFactoryResolver: ComponentFactoryResolver,
    private webmapService: WebMapService
  ) {}

  @ViewChild(ContainerDirective, { static: true })
  componentContainer: ContainerDirective;

  private openedComponents = {};

  private events = [];

  /* istanbul ignore next */
  ngOnInit(): void {
    this.events.push(
      this.webmapService.core.getEvent().subscribe('showForm', (url) => {
        this.navigateToForm(url);
      })
    );
    this.events.push(
      this.webmapService.core.getEvent().subscribe('closeForm', (url) => {
        this.disposeComponent(url);
      })
    );
  }

  /**
   * Load a new component inside the formsContainerComponent
   * @param url the url object of the component.
   */
  /* istanbul ignore next */
  navigateToForm(id: any): void {
      const componentType = TypeResolver.getType(id);
      /* istanbul ignore else */
      if (!componentType) {
        WMLogger.instance()
          .error(`There is not a type registered with the name ${id} in the TypeResolver.
        Please check that the name is well written or the dataTransfer is the same in the backend`);
        return;
      }
      this.loadComponent(componentType, id);
  }

  /**
   * Creates a new component instance inside the formscontainer component
   * @param componentToLoad The new component to load
   * @param name The name of the component.
   */
  /* istanbul ignore next */
  loadComponent(componentToLoad: any, id: any): ComponentRef<any> {
    const componentFactory =
      this.componentFactoryResolver.resolveComponentFactory(componentToLoad);
    const viewContainerRef = this.componentContainer.viewContainerRef;
    const componentRef = viewContainerRef.createComponent(
      componentFactory
    ) as ComponentRef<any>;
    if (componentRef.instance.afterLoadComponent) {
      componentRef.instance.afterLoadComponent();
    }
    this.openedComponents[id] = componentRef;
    return componentRef;
  }

  /**
   *  Removes a component inside the formsContainerComponent
   * @param url the url object of the component.
   */
  /* istanbul ignore next */
  disposeComponent(id: any): void {
    if (id && this.openedComponents[id] && this.openedComponents[id].hostView) {
      const viewContainerRef = this.componentContainer.viewContainerRef;
      const vcrIndex = viewContainerRef.indexOf(
        this.openedComponents[id].hostView
      );
      try {
        viewContainerRef.remove(vcrIndex);
      } catch (e) {
        // Avoid triggering synchronization error while deleting the component.
        WMLogger.instance().debug(e);
      }
      delete this.openedComponents[id];
    } else {
      WMLogger.instance().debug(`The view ${id} to be removed was not found:
      ${
        this.openedComponents[id]
          ? 'HostView property undefined.'
          : ' The view is not present in the openedComponents collection.'
      }`);
    }
  }

  /**
   * Executes on component destroy to unsubscribe the events
   */
  ngOnDestroy(): void {
    this.events.forEach((evnt) => {
      this.webmapService.core.getEvent().unSubscribe(evnt);
    });
  }
}

```

{% endtab %}

{% tab title="no-web-map-forms-container.component.html" %}

```markup
<ng-template wm-content></ng-template>

```

{% endtab %}

{% tab title="no-web-map-forms-container.components.css" %}

```css
/* Empty css file*/
```

{% endtab %}
{% endtabs %}

Notice how, inside of the ngOnInit method. the showForm and closeForm events are subscribed to the WebMap service. These subscriptions are the ones that handle the open/close of the non-WebMap forms.

The second step is to create a new Angular form to add (for this example, we will call the new angular component "heroes").

To accomplish this, first create the Hero interface:

{% tabs %}
{% tab title="hero.ts" %}

```typescript
export interface Hero {
    id: number;
    name: string;
}
```

{% endtab %}
{% endtabs %}

Then, create a file called **mock-heroes.ts** that contains the Heroes list constant.

{% tabs %}
{% tab title="mock-heroes.ts" %}

```javascript
import { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 12, name: 'Dr. Nice' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr. IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];
```

{% endtab %}
{% endtabs %}

The following elements must be added in *heroes.components.ts* :

1. Add the WebMap dataTransfer decoration. The *dataTransfer* defines a unique identifier for the form. This will be used later by the **nowebmapformscontainercomponent** to know which form should be opened or closed.
2. Inject the WebMapService to the form. This service will be used to trigger the closeForm event from the form.

{% tabs %}
{% tab title="heroes.component.ts" %}

```typescript
import { Component } from '@angular/core';
import { Hero } from '../../hero';
import { HEROES } from '../../mock-heroes';
import { dataTransfer} from "@mobilize/base-components";
import { WebMapService} from "@mobilize/angularclient";

@Component({
  selector: 'heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
@dataTransfer(["HeroesComponent"])
export class HeroesComponent {
  constructor(private wmservice : WebMapService) {}

  heroes = HEROES;
  selectedHero?: Hero;

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }

  close() {
    this.wmservice.core.getEvent().publish('closeForm', 'HeroesComponent');
  }
}
```

{% endtab %}

{% tab title="heroes.component.html" %}

```markup
<kendo-window
title="Non webmap form"
(close)="close()"
[minWidth]="250"
        [width]="450"
>
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

<div *ngIf="selectedHero">

  <h2>{{selectedHero.name | uppercase}} Details</h2>
  <div><span>id: </span>{{selectedHero.id}}</div>
  <div>
    <label for="hero-name">Hero name: </label>
    <input id="hero-name" [(ngModel)]="selectedHero.name" placeholder="name">
  </div>

</div>
</kendo-window>
```

{% endtab %}

{% tab title="heroes.component.css" %}

```css
/* HeroesComponent's private CSS styles */
.heroes {
    margin: 0 0 2em 0;
    list-style-type: none;
    padding: 0;
    width: 15em;
  }
  .heroes li {
    cursor: pointer;
    position: relative;
    left: 0;
    background-color: #EEE;
    margin: .5em;
    padding: .3em 0;
    height: 1.6em;
    border-radius: 4px;
  }
  .heroes li:hover {
    color: #2c3a41;
    background-color: #e6e6e6;
    left: .1em;
  }
  .heroes li.selected {
    background-color: black;
    color: white;
  }
  .heroes li.selected:hover {
    background-color: #505050;
    color: white;
  }
  .heroes li.selected:active {
    background-color: black;
    color: white;
  }
  .heroes .badge {
    display: inline-block;
    font-size: small;
    color: white;
    padding: 0.8em 0.7em 0 0.7em;
    background-color:#405061;
    line-height: 1em;
    position: relative;
    left: -1px;
    top: -4px;
    height: 1.8em;
    margin-right: .8em;
    border-radius: 4px 0 0 4px;
  }
  
  input {
    padding: .5rem;
  }
```

{% endtab %}
{% endtabs %}

Once both components are created, the third step is to include them in the **app.module.ts** file. Besides, the selector of the **nowebmapformscontainercomponent** should be added to the **app.component.html**.

The non-WebMap component should be added in both declarations and bootstrap sections.

{% tabs %}
{% tab title="app.module.ts" %}

```typescript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NgZone, ChangeDetectorRef} from '@angular/core';
import { AppComponent } from './app.component';
import { BaseComponentsModule } from '@mobilize/base-components';
import { WebMapKendoModule } from '@mobilize/winforms-components';
import { WebMapService, WebMapModule } from '@mobilize/angularclient';
import { HeroesComponent } from './components/heroes/heroes.component';
import { NoWebMapFormsContainerComponent } from './components/no-web-map-forms-container/no-web-map-forms-container.component';
import { WindowModule } from "@progress/kendo-angular-dialog";
@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent,
    NoWebMapFormsContainerComponent,
  ],
  imports: [
    BrowserModule,
    BaseComponentsModule,
    WebMapKendoModule,
    WebMapModule,
    WindowModule,
  ],
  providers: [WebMapService  ],
  bootstrap: [AppComponent, HeroesComponent],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }
```

{% endtab %}

{% tab title="app.component.html" %}

```markup
<div>
    <wm-formscontainer></wm-formscontainer>
    <wm-loading></wm-loading>
    <wm-background-worker [url]="'/bgw'"></wm-background-worker>
    <wm-nowebmapformscontainer></wm-nowebmapformscontainer>
</div>
```

{% endtab %}
{% endtabs %}

Using a FrontEnd handler just like the one described in the last post, the developer can open a Non-WebMap form in the following way:

```typescript
WebMapService.currentService.core.getEvent().publish('showForm', 'HeroesComponent');
```

Please notice that opening the form just consists of publishing the **showForm** event and passing the data transfer of the form the developer wants to open.

Closing the form works in a similar way. For example, on the close method of the **HeroesComponent** you will find that the **closeForm** event is published passing the datatransfer of the HeroesComponent to close it.

To test this example, you must compile the angular project with all the changes described before and run the app. Then, you will have to click on the element with the frontend handler where the publish of the showForm event was added.

![The Non WebMAP form opened](/files/zV8OGKRw86RN06tbOzXi)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.gapvelocity.ai/webmap/winforms/extend-or-modify-the-converted-application/adding-non-webmap-angular-forms.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
