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 best way to pass a variable from a class and function to another component in an Angular application?

One of the components in my project is called flow.component.ts and here is a snippet of the code: var rsi_result: number[]; @Component({ selector: 'flow-home', templateUrl: './flow.component.html', styleUrls: ['./flow.comp ...

Angular Error TS2339: The property 'car' is missing from type 'Array of Vehicles'

Encountering Angular Error TS2339: Property 'vehicle' is not found on type 'Vehicle[]'. The error is occurring on data.vehicle.results. Any thoughts on what could be causing this issue? Is the problem related to the Vehicle model? I hav ...

Retrieve and manipulate custom headers from a webview within an AngularJS app

I have implemented an angular application within a webview using the following code: WebView.loadUrl(String url, Map<String, String> additionalHttpHeaders) In order to manage the content and display it appropriately, I am maintaining a state in my ...

Using Nest JS to create two instances of a single provider

While running a test suite, I noticed that there are two instances of the same provider alive - one for the implementation and another for the real implementation. I reached this conclusion because when I tried to replace a method with jest.fn call in my ...

Using AngularJS, receive confirmation of file download completion from the client's browser

Seeking advice on how to receive a response after each file download (successful or unsuccessful) from the client browser using AngularJS for my frontend. Feeling confused and unsure of what steps to take. Any guidance would be greatly appreciated. ...

What is the method in XState to trigger an event with the parameters send('EVENT_NAME', {to: 'a value from the context'})?

I want to send an event to a different spawned state machine using its ID, which I have stored as a string in a variable within the context. This state machine is neither the parent nor child. For example: context.sendTo = 'B_id' How can I use ...

The directive fails to refresh when there are modifications made to the service model

My application's model is stored in a service: angular.module('adminClient').factory('myApi', function () { var model = {}; model.myObject = { label: 'New York City' }; return { model: fu ...

Tips for temporarily preventing a digest cycle when modifying a scope variable

Is there a way to edit an array of objects in AngularJS, linked to the view through ng-repeat, without updating the scope until all objects have been modified? Consider this scenario: I need to update each object in the array and only then reflect the ch ...

Issues with tracking changes in Vue.js when using reactive variables

After triggering a click event, I am attempting to choose a message from a json file. However, I am encountering an issue where the first click does not seem to select anything. Upon the second click, the selected messages are duplicated, and this pattern ...

What kind of function possesses additional attributes or characteristics?

I am finding it difficult to define the type for the function foo as demonstrated below: function foo() { do something } foo.boo = () => { do something else } foo("hello"); foo.boo("hello"); This JavaScript code is functioning corr ...

Utilize URL parameters in Node.js and Express for effective communication

I have an endpoint ..com When I perform a curl call, the endpoint looks like this: ..com?param1=true Now, I am attempting to make a similar call from Node.js. However, I'm uncertain about whether param1 should be included in the headers, concatenate ...

How can I pass $scope between controllers in AngularJS?

Just starting out with Angular Js. Can I pass the scope of the RestaurantController to the MenuController like this? For example: angular.module('restaurants').controller('RestaurantController', ['$scope', function($sco ...

Having trouble importing moment-range into your Angular 4.x application using ES6? Getting an error about incompatible call signatures?

In my Angular 4.x application, I encountered an issue while trying to import the moment-range package. The official documentation suggests using the following code: import Moment from 'moment'; import { extendMoment } from 'moment-range&apo ...

Different types of subscriptions for forkJoin observable

I am currently making two API requests with typed responses and combining them using the Observable.forkJoin method. My goal is to store each of the results in separate typed variables. var observableOrganization: Observable<Organization> = this.get ...

Incorporating library files (css/js) into your app built on the angular-fullstack framework

After using a Yo Angular-Fullstack generator (https://github.com/DaftMonk/generator-angular-fullstack) to start an app, I attempted to install Toastr from bower with the command: bower install angular-toastr Now, I need to add the toastr css and js files ...

Self-referencing type alias creates a circular reference

What causes the discrepancy between these two examples? type Foo = { x: Foo } and this: type Bar<A> = { x: A } type Foo = Bar<Foo> // ^^^ Type alias 'Foo' circularly references itself Aren't they supposed to have the same o ...

Looking to incorporate an additional column 'LastName' that can be used for filtering in the Angular data table code. This column will be included if it is present in the data

function applyFilter(filterValue: string) { filterValue = filterValue.toLowerCase(); --- return filtered result return this.dataSet.filter( (item: any) => item.name ? item.name.toLowerCase(). ...

Getting the Right Value: A Step-by-Step Guide to Setting the Default or Selected Value in

When creating directive form controls (text, select, radio), I am passing a value to the directive function. If this value is not set or empty, then the default value should be taken from the question data._pageAttributes.defaultValue. HTML <div ng-re ...

Utilizing $http (REST) to send information from a form

Struggling to leverage Angular for CRUD processes, especially encountering difficulties with POST requests to the server. This is my controller: angular.module('myModule').controller("ListingCtrl", function($scope, posts) { $scope.addProje ...

Angular Digest Loop for Dynamic Photo Grid Styling

I have a special filter that alters the objects being filtered. However, when I apply ng-style="item.gridSize", it triggers my custom grid algorithm. This algorithm was adapted for my requirements from a source found at this link. angular.module("custom.m ...