Is there a way for me to monitor the ngSrc attribute of an image element and retrieve the updated width and height within my personalized directive?

Here is a snippet from index.html:

<img ng-src="{{ImageURL}}"  my-image/>

This is from app.js:

var app = angular.module('plunker', []);

app.controller('MyCtl', function($scope) {

  $scope.ImageURL = "";
  $scope.ImgWidth = 0;

  $scope.setImgSrc = function(imgURL) {
    $scope.ImageURL = imgURL;
  };

  $scope.setImgSrc('http://angularjs.org/img/AngularJS-large.png');

});

app.directive('myImage', [function() {

  return function(scope, elm, attrs) {

    scope.$watch(elm.width(), function(newValue, oldValue) {

      scope.ImgWidth = newValue; // always returns 0!

    });

  };

}]);

If you're curious or have a solution, check out the plunk. How can I retrieve the new dimensions of the image element in my custom directive when the ngSrc attribute changes? My suspicion is that there may be an issue with how I'm utilizing scope.$watch.

Answer №1

It appears that the watch on your plunk is accurate, unlike the example on SO which may not deliver the expected results.

In order for a watch expression to work properly, it should either be a string expression or a function. The example provided shows an attempt to watch the result of elm.width(), which likely returns 0. Essentially, this is akin to

scope.$watch(0, function() {...})
. If monitoring width changes is the goal, the proper approach would involve using
scope.$watch(function() { return elm.width(); }, function() {...})
. However, frequent access to the DOM through watch expressions is generally discouraged.

A more efficient alternative involves waiting until the image loads (using the load event) and updating measurements at that point. This way, DOM manipulation only occurs when necessary. For implementation details, refer to the updated plunk here.

Answer №2

Due to the small size of the image, it is probably not noticeable, but the width is being obtained before the image has fully loaded. To address this issue, you can add an 'on load' event to the element.

app.directive('myImage', [function() {
    return function(scope, elm, attrs) {
      elm.on('load', function()
      {
        scope.ImgWidth = $(this).width();
        scope.$apply();
      });
    };
}]);

Answer №3

Your issue lies within the $watch function you are using. It requires the first argument to be a string for evaluation or a function that can be called to check values. You have passed an integer instead of meeting these requirements. Consider updating your code like this:

 scope.$watch(function() { return elm.width(); }, function(newValue, oldValue) {
     scope.ImageWidth = newValue;
 });

You can find the updated Plunk here: http://plnkr.co/edit/93SvAosQWkQzRq0DFXaK?p=preview

Additionally, make sure to include the complete jQuery library to access the width() function as demonstrated in my example.

Update - I have modified the Plunk based on @Andyrooger's suggestion to handle the load event. Ideally, fetching the width within the load event handler would be more efficient, but I have kept it as is to address the $watch method mentioned in the original question.

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

refreshing datatables with updated data from a different endpoint

Need help reloading datatables with the new ajax feature? I suspect it might be a scope issue. function refreshTable(tableName, src) { var table = $('#'+tableName).DataTable({ 'bProcessing': true, 'bServerSide ...

Clicking does not trigger scrollIntoView to work properly

I'm facing an issue with a button that is supposed to scroll the page down to a specific div when clicked. I implemented a scrollIntoView function in JavaScript and attached it to the button using onClick. Although the onClick event is functioning as ...

"How can you enhance the performance of JavaScript and CSS in a Chrome Extension without using exclude_matches/globs or excluding domains

I have been in the process of creating a Chrome Extension, and unfortunately, when I tried to make it work on specific URLs, I encountered an issue. While Chrome has options like exclude_matches and exclude_globs for this purpose, there seems to be a bug i ...

Leveraging the power of Angular to seamlessly update and manipulate data in Highcharts using the highcharts

Exploring the capabilities of a highcharts directive designed for angular, known as highcharts-ng. Check it out on GitHub. Encountering an issue with updating the data when using the directive. While updating the series values is successful, facing diffic ...

Generate a fresh row in a table with user inputs and save the input values when the "save" button is

HTML: <tbody> <tr id="hiddenRow"> <td> <button id="saveBtn" class="btn btn-success btn-xs">save</button> </td> <td id="firstName"> <input id="first" type="tex ...

axios does not distinguish between response and error in its return value

I have created a React component that contains a function called onFormSubmit. This function calls another function from a separate component, which in turn makes a POST request using axios. I want the ability to return a response if the POST request is su ...

Exploring different methods to locate a random ID using XPATH, CSS path, and selector while conducting Selenium c# testing on a CMS tool

Issue: Hey there, I'm currently working on testing a CMS tool with selenium in C#. The problem I'm facing is finding a suitable selector for a small drop-down button due to the random generation of IDs for all selectors. Every time the script run ...

Enabling AJAX calls to backend service through nginx proxy by filtering based on request_method

As a newcomer to Nginx, please bear with me if my question seems naive. I have set up a service behind an nginx proxy with auth_basic to restrict access. However, I now need to allow an Angular app to interact with this service while controlling which requ ...

Avoid running the second then() function in a promise if a specific condition is satisfied

Can anyone help me figure out how to prevent the code block below from executing any further once arkIsEnabled is evaluated as true? return promise .then(response => { if (arkIsEnabled) { dispatch(createArk(respo ...

Unable to display the string following a space in the value attribute of an hbs file

<input type="text" class="form-control" id="exampleInputEmail2" name="productName" value={{product.productName}} > When I input 'Smart Phones' into product.produc ...

Looking for guidance on implementing a server-side 310 redirect and mod rewrite on a stamplay server?

In Angular framework, there is an option to eliminate the # symbol from the URL by setting $locationProvider.html5Mode(true);. This results in aesthetically pleasing URLs and facilitates proper sharing on platforms like Facebook, as complete URLs are pas ...

Implementation of Exporting to Excel

function fnshowAuditList() { if(auditListTable) auditListTable.fnDestroy(); jQuery.ajax({ type: 'POST', url: 'auditListAction', data: '', dataType: 'text&a ...

Is there a way to deactivate the minutes input feature in the Angular UI Timepicker?

I am using a plugin that displays the time in hours and minutes. However, I only need to show the hours. Is there a way to hide the minutes block? This is my HTML code: <uib-timepicker ng-model="mytime" ng-change="changed()" hour-step="1" minute-step ...

Exploring the capabilities of transform and duplex streams in NodeJS

Collecting data from an external source via Bluetooth Low Energy using NodeJS (noble module) and storing it in a JSON array file named fromSource.json: [ { "id": 1, "name": "foo", "value": 123 }, { "id": ...

The width:auto attribute for images in ie6 is not functioning as expected

I am facing a challenge with dynamically changing and resizing an image element to fit its container. My current approach involves: Resetting the image: // Ensuring the 'load' event is re-triggered img.src = ""; // Resetting dimensions img. ...

Using VueJS for reactive binding效果

I am attempting to assign a class using the following syntax: :class="{active: favs.medium_title.fontWeight === 'bold'}" However, the fontWeight attribute is not yet defined when the component loads. This is an excerpt from my object: favs: { ...

Steps to load data using ajax-php with specific parameters

I have a situation where I need to trigger a JavaScript function when a link is clicked. <input type='hidden' id='name'> <a href='#' onclick='getUsers(1)'>Click here</a> function getUsers(id){ $( ...

"Integrating multiple partials with templateUrl in AngularJS: A step-by-step

Is there a way to merge partial views using the templateUrl attribute in an AngularJS directive? Imagine having a directive like this: .directive('combinePartials', function () { var mainPartial = "mainpartial.html", var template2 = "pa ...

Error: Unable to locate the tslint command

After attempting to utilize tslint --fix, I encountered the error message bash: tslint: command not found.... To install tslint, I ran the following command: yarn global add tslint typescript. The operating system on my machine is Centos 7. ...

Unexpected Results: React Multiline MUI Text Box Fails to Show Intended Content

In the process of developing a React application, I have come across a requirement to implement a multiline text box for editing job advertisements. The text box should initially display a default value containing dynamic placeholders such as [displayTitle ...