Controller property not being updated by directive

I have developed a custom directive to identify when the enter key is pressed within a text box. Here's the implementation of the directive:

import { BookmarkService } from "../services/bookmarkService";
import { qlik, QlikBookmarkInfo } from "../qlikInit";

class BookmarkListController {
/**
 * Dependency injection params
 */
public static $inject: string[] = ["$scope", "bookmarkSvc"];

private $scope: ng.IScope;
private bookmarkSvc: BookmarkService;
private bookmark: QlikBookmarkInfo;
private bookmarkIndex: number;
private showToolbar: boolean = false;
public showAddTextbox: boolean = false;
public newBookmarkTitle: string = "";
private showEditBookmark: boolean = false;

public constructor(scope: ng.IScope, bookmarkSvc: BookmarkService) {
    this.$scope = scope;
    this.bookmarkSvc = bookmarkSvc;
}

public applyBookmark(bookmarkId: string, bookmarkTitle: string, bookmarkDescription: string): void {
    this.bookmark = {Id: "", Title: "", Description: ""};
    this.bookmark.Id = bookmarkId;
    this.bookmark.Title = bookmarkTitle;
    this.bookmark.Description = bookmarkDescription;
    this.showToolbar = true;
    qlik.applyBookmark("ABC", bookmarkId);
}

public createBookmark(): void {
    this.showAddTextbox = true;
}

public removeBookmark(): void {
    qlik.removeBookmark("ABC", this.bookmark.Id);
    this.bookmarkIndex = this.bookmarkSvc.bookmarksInfo.indexOf(this.bookmark);
    this.bookmarkSvc.bookmarksInfo.splice(this.bookmarkIndex, 1);
    this.showToolbar = false;
}

public editBookmark(): void {
    this.showEditBookmark = true;
    // do something
}

/* tslint:disable:no-any */
public saveBookmark(e: any): void {
    if (e.keyCode === 13) {
        qlik.createBookmark("ABC", this.newBookmarkTitle);
        this.showAddTextbox = false;
        this.newBookmarkTitle = "";
    }
}
/* tslint:enable:no-any */
}

export class BookmarkListComponent implements ng.IComponentOptions {
public templateUrl: string = "bookmarkList.html";
public controller: Function = BookmarkListController;
}

export function bookmarkEnter(): ng.IDirective {
return<ng.IDirective>{
    restrict: "A",
    scope: {
        showAddTextbox: "=?",
        newBookmarkTitle: "=?"
    },
    link: (scope: ng.IScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes, controller: BookmarkListController): void => {
        element.on("keyup", (e: any): void => {
            if (e.keyCode === 13) {
                qlik.createBookmark("ABC", controller.newBookmarkTitle);
                scope.$apply((): void => {
                    controller.showAddTextbox = false;
                    controller.newBookmarkTitle = "";
                });
            }
        });
    },
    controller: BookmarkListController,
    controllerAs: "$ctrlblc",
    bindToController: true
};
}

Incorporating the directive as below in a bookmarkList.html file:

<div class="dsh-ListTitle">
<h4 class="dsh-ListTitle-title">Bookmarks</h4>
<a class="dsh-List-item" ng-click="$ctrl.createBookmark()">
    <ers-icon name="add" ers-tooltip="Add Bookmark"></ers-icon>
</a>
</div>
<div class="u-flex dsh-List dsh-List-icon" ng-show="$ctrl.showToolbar">
<a class="dsh-List-item" ng-click="$ctrl.editBookmark()">
    <ers-icon name="edit" ers-tooltip="Edit Bookmark"></ers-icon>
</a>
<a class="dsh-List-item" ng-click="$ctrl.removeBookmark()">
    <ers-icon name="delete" ers-tooltip="Delete Bookmark"></ers-icon>
</a>    
</div>
<ul class="dsh-List">
<li class="dsh-List-item" ng-repeat="bookmark in $ctrl.bookmarkSvc.bookmarksInfo">
    <a ng-click="$ctrl.applyBookmark(bookmark.Id, bookmark.Title, bookmark.Description)">{{bookmark.Title}}</a>
</li>
<li class="dsh-List-item" ng-show="$ctrl.showAddTextbox">
    <input type="text" bookmark-enter showAddTextbox="$ctrl.showAddTextbox" newBookmarkTitle="$ctrl.newBookmarkTitle" ng-show="$ctrl.showAddTextbox"/>        
</li>
</ul>

I believe I've correctly connected everything. However, when executing qlik.createBookmark(), the controller.newBookmarkTitle doesn't capture the text entered in the text box. It shows up as an empty string. Meanwhile, evaluating element.val() does contain the typed text.

What could I be overlooking here? The project employs AngularJS version 1.5.

Answer №1

Your main mistake lies in the naming of attributes that you are passing to the directive.
To clarify, if you define scope: {showAddTextbox: '=?'} using camelCase, you should pass the attribute in the HTML with kebab-case like

<input bookmark-enter show-add-textbox="$ctrl.showAddTextbox"
.
Additionally, replace controller. with scope. in your link function when referencing your directive's parameters.

** As a suggestion, instead of using $scope.apply(), consider using $scope.applyAsync() or

$timeout(function(){ //your code })
. This can help avoid the angularjs error $digest already in progress.

EXAMPLE:

HTML

<input type="text" bookmark-enter show-add-textbox="$ctrl.showAddTextbox" ng-model="$ctrl.newBookmarkTitle" ng-show="$ctrl.showAddTextbox"/>

DIRECTIVE

restrict: "A",
scope: {
    showAddTextbox: "=?",
    newBookmarkTitle: "=ngModel"
},
link: (scope: ng.IScope, element: ng.IAugmentedJQuery, attributes: ng.IAttributes, controller: BookmarkListController): void => {
    element.on("keyup", (e: any): void => {
        if (e.keyCode === 13) {
            qlik.createBookmark("ABC", scope.newBookmarkTitle);
            scope.$timeout(() => {
                scope.showAddTextbox = false;
                scope.newBookmarkTitle = "";
            });
        }
    });
},

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the most efficient way to use map-reduce in TypeScript to filter a list based on the maximum value of an attribute?

Recently, I came across a list that looked something like this: let scores = [{name: "A", skills: 50, result: 80}, {name: "B", skills: 40, result: 90}, {name: "C", skills: 60, result: 60}, {name: "D", skills: 60, ...

What is the best way to add a change event to a textarea that is already applied with a filtered one-way binding?

I have a text area that is already linked with a filter, so it will display the correct information when the page loads. Now, I want to update a model when the text area content changes. However, when I add a model and change event, the initial binding sto ...

ERROR: Unable to call function getTime in Typescript

While working on my function in Typescript, I encountered an issue with two sets of data in the database - date and time, both expecting strings. When users select a date, I trigger a POST request to set the time for them. To handle this scenario, I creat ...

Error: The AppModule is missing a provider for the Function in the RouterModule, causing a NullInjectorError

https://i.stack.imgur.com/uKKKp.png Lately, I delved into the world of Angular and encountered a perplexing issue in my initial project. The problem arises when I attempt to run the application using ng serve.https://i.stack.imgur.com/H0hEL.png ...

Access and retrieve dynamically generated table row values with the use of AngularJS

Hi, I'm new to angularjs and I have a table where I need to dynamically add rows. I've got everything working with a bit of JQuery but I'm having trouble getting the value of dynamically created table rows. Here's my code, can someone p ...

How can I configure React Router V6 to include multiple :id parameters in a Route path, with some being optional?

Currently, I am utilizing react-router@6 and have a Route that was previously used in V5. The route is for vehicles and always requires one parameter (:id = vehicle id), but it also has an optional second parameter (:date = string in DD-MM-YYYY format): &l ...

Application route is failing to direct to the HTML page

On my MEAN stack website, I am trying to make the browser navigate to a file named 'findCable.html' but it keeps directing to 'singleCable.html'. I have double-checked the angular routing file and backend routes, but can't see ...

Unlocking the accordion feature in Ionic 3 form: A step-by-step guide

I am currently working on a search form and want to incorporate it within an accordion so that users can simply click to expand the form. Below is the code snippet: TS. buildForm(): void { this.form = this.fb.group({ username: new FormControl(& ...

toggle visibility of <li> elements using ng-repeat and conditional rendering

I have an array of color IDs and codes that I'm utilizing with ng-repeat in the <li> tag to showcase all colors. However, I only want to display colors where the color code is less than 10, hiding any colors where the color code exceeds 10. Addi ...

Using Angular to pass an index to a pipe function

Currently, I am attempting to incorporate the *ngFor index into my pipe in the following manner: <td *ngFor="let course of courses | matchesTime:time | matchesWeekday:i ; index as i">{{course.courseName}}</td> This is how my pipe is structure ...

What is the best way to retrieve the content of HTML tags from a string using JavaScript or AngularJS?

I have a string with mixed content of HTML tags and text. Here is an example: var str = "<p></p><p><i>blabla</i></p><p><i><b>blaaaaaablaaaaa</b></i></p><iframe src="..." height=" ...

Guide on transferring object between two $states using ui-router

Visit this link for more information Expected Behavior Upon logging in, selecting a Ticker button is expected to trigger the display of matching Tags for that specific Ticker. Actual Results However, upon clicking a Ticker button after logging in, the ...

Learning how to merge two observable streams in Angular2 by utilizing RxJS and the powerful .flatMap method

Within my Angular2 app, I have created an Observable in a Service called ContentService. Here is a simplified version of the code: @Injectable() export class ContentService { constructor(private http:Http, private apiService:ApiService) { th ...

Tools needed for Angular project development

Currently, I am engaged in a project using AngularJS on a Windows 7 computer. My desire is to be able to seamlessly transition between working at the office and working from home or any other location. If I have everything installed in a folder named C:/C ...

Enlarging the modal overlay

My Angular/Bootstrap app features a small text area within a modal window that often contains lengthy content exceeding the size of the textarea and modal itself. I am looking to incorporate a button within the modal window that, when clicked, opens a lar ...

Is there a mistake in the TypeScript guide for custom typography in MUI5?

Currently, I am in the process of setting up custom typography variants in MUI5 by referencing this helpful guide: https://mui.com/customization/typography/#adding-amp-disabling-variants. As I follow step 2 and input the type definitions: declare module &a ...

I am seeking advice on how to create an extension for a generic class in TypeScript specifically as a getter

Recently, I discovered how to create extensions in TypeScript: interface Array<T> { lastIndex(): number } Array.prototype.lastIndex = function (): number { return this.length - 1 } Now, I want to figure out how to make a getter from it. For exam ...

Arranging elements within an outer array by the contents of their inner arrays

I need help organizing an array based on the alphabetical order of a specific value within the inner arrays. For example: I want to sort this array by the prefix "old," so old A, old B, etc. const array = [ { personName: "Vans", personTags: ["young", " ...

Storing data in Angular service for future use

My ui-grid is functioning correctly, utilizing server side pagination with a view button to display row details on a separate page. However, upon returning to the grid after viewing details, it defaults back to displaying the first page. I would like it to ...

creating dynamic lists in angular.js

Could you please guide me on creating a dynamic list in Angular.js? I have successfully implemented a feature where users can add items to the list by clicking a button and filling out the required fields. To see this in action, check out this fiddle: http ...