What is the best way to create a dynamic-width text input with ellipsis and label in Angular?

I am looking to incorporate a <input type="text"> element in my Angular application that will automatically display an ellipsis if the user-provided value is too lengthy to fit within the UI, unless being edited.

This text input will have a dynamic width and be accompanied by a one-line label positioned next to it. The input field should expand to fill all available space after the label.

Additionally, I want to ensure that the labels remain one-line regardless of their length.

Although I understand that regular HTML text inputs (<input>) cannot have ellipsis applied to them, only standard HTML elements like <div>, is there a way to achieve this effect with an input element?

Answer №1

Check out this code snippet

https://i.sstatic.net/KgLZP.png

There are several components in action:

  • The value is shown as a regular <span> (to display ellipsis), and when clicked, the <input> replaces it (controlled by the editing variable)
  • A directive called focusMe is used to focus on the newly created <input> replacing the <span>
  • A filter named nonBreaking ensures that the text label is displayed in a single line
  • CSS rules utilizing flexbox control the layout
  • Properties like overflow, text-overflow handle the appearance of ellipsis
  • white-space: nowrap and flex-shrink: 0 prevent breaking the text label into multiple lines
  • flex-grow: 1 ensures that the <input> expands to fill extra space available

Disadvantages:

  • Clicking on the static <span> places the cursor at the beginning of the <input>, not where the user clicked (especially if clicking in the middle)
  • If labels exceed viewport width, the text input won't be visible (assuming the viewport is wider than the label length)

Additional information:

When adding validation, keeping the <input> visible for invalid data prevents an empty span when the model is invalid.

To achieve this:

  • Pass "name" to the directive and include <input name="{{name}}"> inside
  • Update to
    <span ng-show="!editing && form.{{name}}.$valid">
  • Modify to
    <input ng-show="editing || !form.{{name}}.$valid">

Complete code:

HTML:

<!doctype html>
<html ng-app="plunker">
<head>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css">
  <script type="text/ng-template" id="InputTextWithEllipsis.html">
    <div class="input-text-with-ellipsis-wrapper">
      <label class="mylabel" ng-bind-html="mylabel | nonBreaking"></label>
      <span class="dual-input-wrapper">
        <span
          ng-show="!editing"
          ng-click="editing = true"
          class="static-text-with-ellipsis">{{mymodel}}</span>
        <input
          ng-show="editing"
          ng-focus="editing = true"
          ng-blur="editing = false"
          focus-me="editing"
          ng-model="mymodel"
          class="editable-textinput" />
      </span>
    </div>
  </script>
</head>
<body ng-controller="MainCtrl">
  <form name="profile">
    <input-text-with-ellipsis
      mylabel="'Name'"
      mymodel="dataModel.name"
    ></input-text-with-ellipsis>

    <input-text-with-ellipsis
      mylabel="'Last Name'"
      mymodel="dataModel.lastName"
    ></input-text-with-ellipsis>

    <input-text-with-ellipsis
      mylabel="'A very long label here'"
      mymodel="dataModel.lastName"
    ></input-text-with-ellipsis>
  </form>
</body>
</html>

JS:

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

myModule.filter('nonBreaking', function($sce) {
  return function(inputStr) {
    var outputStr = inputStr.replace(/\s/g, '&nbsp;');
    return $sce.trustAsHtml(outputStr);
  };
});

/*
 * http://stackoverflow.com/a/14837021/245966
 */
myModule.directive('focusMe', function($timeout, $parse) {
  return {
    link: function(scope, element, attrs) {
      var model = $parse(attrs.focusMe);
      scope.$watch(model, function(value) {
        if (value === true) {
          $timeout(function() {
            element[0].focus();
          });
        }
      });
    }
  };
});

myModule.controller('MainCtrl', function($scope) {
  $scope.dataModel = {
    name: "Fernando",
    lastName: "Fernandez Sanchez de la Frontera"
  }
});

myModule.directive('inputTextWithEllipsis', function(){
  return {
    restrict: 'E',
    templateUrl: 'InputTextWithEllipsis.html',
    require: ['^form'],
    scope: {
      mylabel: '=',
      mymodel: '='
    },
    link: function(scope, element, attrs, ctrls) {
      scope.editing = false;
    }
  };
});

CSS:

* {
  font: 16pt sans-serif;
  border: 0;
  padding: 0;
  margin: 0;
  outline: 0;
}

.input-text-with-ellipsis-wrapper {
  background-color: linen;
  padding: 10px;

  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
}

.mylabel {
  background-color: #ffddcc;
  margin-right: 10px;

  flex-basis: auto;
  flex-shrink: 0;
  min-width: 50px;
}

.dual-input-wrapper {
  flex-basis: auto;
  flex-grow: 1;
  overflow: hidden;
  white-space: nowrap;
  text-align: right;
}

.editable-textinput {
  background-color: #ddf;

  width: 100%;
  text-align: right;
}

.static-text-with-ellipsis {
  background-color: #eeccbb;

  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
}

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

Oops! Looks like a problem with the controller registration in this code: "[$controller:ctrlreg] http://errors.angularjs.org/1.7.4/$controller/ctrlreg?p0=App

My goal is to create a multilingual website, but I encountered an issue when trying to switch between languages. An error message appeared in the console and prevented the language change from happening. Index.html <html ng-app='mpdmApp' lan ...

Utilizing Vue.js and Webpack to Handle Requests for Multiple Incorrect Resource Links

After utilizing Vue.js single file components to construct a website and appreciating the modular approach, I've encountered an issue. The browser appears to be requesting multiple versions of resources instead of just one URL for each. HeaderBar.vue ...

Leveraging TypeScript in Angular 4 for parsing response data

I have received the following response data: { "content": [{ "id": 1, "userName": "v7001", "status": 1, "userInfo": { "id": 1, "fullName": "Naruto Uzumaki", "firstName": "Naruto", "lastName": "Uzumaki", "add ...

Expanding upon the Ember.js Model's save functionality

I have incorporated promise-based code (MyLib) that needs to execute on every model save by extending the save function: DS.Model.extend save: -> parentSave = @_super.bind this, arguments... deferred = Ember.RSVP.defer() MyLib.func().t ...

Determine the RGB color values for specific coordinates within Adobe Illustrator

Currently exploring ExtendScript for JavaScript in Adobe Illustrator 2015. Is there a method to retrieve RGB values based on coordinates within the code below? // initializing document var doc = app.activeDocument; // defining x and y coordinates for colo ...

Removing a user via Fetch API in the delete endpoint

Creating a user website that allows the admin to delete users is my latest project. I've implemented it using an Azure SQL database and have set up an endpoint called deleteUser in my controllers file. deleteUser const deleteUser = (req, res) => { ...

Why isn't the background-image displaying with the use of the url() function?

I've been attempting to set an image as the background using background-img:url(imageLing), but it's not working properly. When I inspect the element, it shows me background-image: url(assets/backgrounds/5.jpg);. What could be causing this issue? ...

Unable to save JSON file

I am encountering an issue with a JSON file I have. The JSON file contains weather data for Munich, including temperature and wind speed information. weather = [ { "city": "Munich", "temp": { "temp_val": "30 deg", ...

Animating UL/LI elements using the power of CSS3 transformations

I am interested in creating animations using CSS3 transitions. Let's consider the following UL/LI element: <ul> <li class="green" id="green" style="display: none;">Contents 1</li> <li class="red" id="red" style="display: ...

How can I position a Font Awesome icon in the center of an image with Bootstrap 3?

I'm attempting to center a font-awesome icon on top of an image within bootstrap 3. Below is the image code enclosed in a div: <div id="quickVideo"> <a data-fancybox href="https://player.vimeo.com/video/153113362?autoplay=1&color=54 ...

The design elements are not being implemented on my custom React library built with TypeScript

I recently created a React library called https://github.com/deadcoder0904/react-typical/ and added styles to the component in the examples/ directory. However, I've noticed that the styles are not being applied. Below is the content of the example/i ...

Pass the result of the callback function from the service to the component

I have integrated the WifiWizard Plugin into my Ionic 2 mobile app using Cordova. It works perfectly fine when I run it in the *.ts file of my page. Here is how my code looks: Declaring WifiWizard before @Component: declare var WifiWizard:any; Using Wif ...

When the mouse is clicked down, make elements move along with the cursor

Is there a way to make picture elements follow the mouse cursor only while the mouse is pressed down? The current script works well but starts following the cursor only after it has been released, which is not the intended behavior. I tried placing the in ...

I am having trouble rendering a simple sphere

I have been closely following the steps outlined in this tutorial: https://www.youtube.com/watch?v=6oFvqLfRnsU to create basic shapes using three.js. I noticed that at the 18:20 mark, the instructor successfully displayed a sphere on the screen. var sc ...

Unable to load images on website

I'm having trouble showing images on my website using Node.js Express and an HBS file. The image is not appearing on the webpage and I'm seeing an error message that says "GET http://localhost:3000/tempelates/P2.jpg 404 (Not Found)" Here is the ...

Output the JSON string retrieved from a specified URL

I'm currently working on using ajax to retrieve and parse JSON data from a specific URL. I am looking for assistance on how to store the parsed array into a variable. Any guidance or suggestions would be greatly appreciated. Thank you! function rvOff ...

Adjust the minimum and maximum values of the Y-axis based on the scale of the X-axis

Currently, I am faced with the challenge of adjusting the Y-axis to scale with changes in X-scale. I have a long unixtime value Array for initializing a flot chart, along with buttons to modify the scale. However, I am struggling to synchronize the Y-axis ...

What steps should I take to pinpoint the fundamental mistake in my webpage dedicated to clocks?

Exploring an intriguing clock project that utilizes ancient timekeeping methods found at . Recently encountered a puzzling error in Chrome, where it claims to be unable to call a method on undefined. Strangely enough, the error message is not located near ...

Using jQuery and JavaScript, start and stop a loop using a single button click

I am looking to create a button that will trigger a JavaScript function when clicked, causing a loop within it to start processing. If the button is clicked again before the loop completes, I want the loop to stop. And if clicked after the loop finishes on ...

Having trouble accessing the ng-model within ng-repeat in the controller of an AngularJS component

One approach I am considering is to use ng-model="model.ind[$index]" in order to keep track of the active tag. This way, when I click on a tag (specifically the 'a' tag), both the parentIndex and $index will be passed to my controller. Subsequent ...