TinyMCE Validating length AngularJs

 
 

I’m creating this “how to…” tutorial based on my experience working with TinyMCE Validating length with Angularjs, and the answers I found in the internet community Stack overflow and github.

What is TinyMce:

It is an opensource WYSIWYG (What You See Is What You Get) HTML editor designed to simplify website content creation. In other words it is a rich text web editor. This is the official website https://www.tinymce.com/

TinyMCE Validating length

TinyMCE Validating length using AngularJs

For the first example I used TinyMCE v4.3.3 with angular-ui-tinymce v0.0.12 plugin and AngularJS v1.4.6.

In the AngularJs controller we have to set the config options, and in the view we use a textarea with the parameter ui-tinymce=”tinymceOptions”


angular.module('myApp', ['ui.tinymce'])
.controller('myCtrl', ['$scope', function($scope) {
    
//set the config options
 $scope.tinymceOptions = {
                    plugins: 'code',
                    toolbar: 'undo redo | bold italic | styleselect | code',
                    menubar: false,
                    forced_root_block: false
                };
// ...
}]);

 
 

<textarea ui-tinymce="tinymceOptions" ng-maxlength="100" 
name="editor" ng-model="vm.editor">
</textarea>
<span ng-show="form.editor.$error.maxlength" class="error">
    100 character limit reached!
</span>

 
 
The code above will not work as it is, because of a known bug https://github.com/angular-ui/ui-tinymce/issues/145

Work around

Took from StackOverflow
One work around can be to disable SCE mode with this code .config([‘$sceProvider’, function($sceProvider) {
$sceProvider.enabled(false);
}])
but…

Beware of security vulnerabilities!

Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain contexts to result in a value that is marked as safe to use for that context. With SCE disabled, an AngularJS application allows to render arbitrary HTML into the div, and rendering user controlled input creates security vulnerabilities.

 
 

angular.module('myApp', ['ui.tinymce'])
.config(['$sceProvider', function($sceProvider) {
    $sceProvider.enabled(false);
}])
.controller('myCtrl', ['$scope', function($scope) {
    
//set the config options
 $scope.tinymceOptions = {
                    plugins: 'code',
                    toolbar: 'undo redo | bold italic | styleselect | code',
                    menubar: false,
                    forced_root_block: false
                };
// ...
}]);

 
 
Here is the JsFiddle https://jsfiddle.net/naXa/zsnLupvd/

Another work arround

This is a directive written by @andresmatasuares for TinyMCE Validating length with AngularJs.

app.directive('plainTextMaxLength', function($filter) {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, element, attributes, ngModel) {
        var maxLength, validPlainTextLength;
        validPlainTextLength = function(v) {
          if (!v) {
            return true;
          }
          return stripHtmlTags(v).length <= maxLength;
        };
        maxLength = void 0;
        scope.$watch(attributes.plainTextMaxLength, function(newValue, oldValue) {
          if (maxLength !== newValue) {
            maxLength = newValue;
            return ngModel.$validate();
          }
        });
        return ngModel.$validators['plainTextMaxLength'] = function(modelValue, viewValue) {
          if (viewValue.$$unwrapTrustedValue) {
            return validPlainTextLength(viewValue.$$unwrapTrustedValue());
          } else {
            return validPlainTextLength(viewValue);
          }
        };
        
      }
    };
  });

 
Here you can find the plunker code http://plnkr.co/edit/oAZcHZAmCXYOTckJCPcs?p=preview

How to use filters within controllers in AngularJs (mini-challenge 12)

filters within controllers

Filters within controllers (mini-challenges 12)

AngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

How would you use filters within controllers like “filter” in JavaScript? And how to create a custom filter?
For example in the html you can use filter’s filter to do a search in a list of elements:

 <tr ng-repeat="friend in friends | filter:searchText">

<table id="searchTextResults">
<tr>
<th>Name</th>
<th>Phone</th>
</tr>

<tr ng-repeat="friend in friends | filter:searchText">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</table>

 
 

Solution:

In AngularJs you can inject the $filter service within the controller, and use it with the following syntax for “filter”:

$filter('filter')(array, expression, comparator, anyPropertyKey)

 

function myController($scope, $filter)
{
   $scope.result = $filter('filter')($scope.arrayOfObjects, $scope.searchCriteria);
}

You can also use other AngularJs filters Build-in like:

 $scope.formatedDate = $filter('date')($scope.date, "yyyy-MM-dd");
 $scope.result = $filter('lowercase')($scope.name);

You can find here a list of build-in AngularJs filters:
https://docs.angularjs.org/api/ng/filter

 
 
Filter Example with pipe in the HTML:

 
 
Filter example within the controller using Javascript:

 
 

How to create custom filters in AngularJs

AngulrJs have a build-in method to register custom filters, using the same approach you can use when you register a controller, a service and factories. See following example:

var myApp = angular.module('myApp', []);
app.filter('myFilter', function() {
  return function(input, option1, option2) {
    var output;
    // Logic to make your filter works.
    return output;
  }
});

 
for more reference about how to create a custom filter you can refer to https://scotch.io/tutorials/building-custom-angularjs-filters
 

Prevent angular executing controller twice (Mini-Challenge 11)

Prevent angular executing controller twice (Mini-Challenge 11)

Prevent angular executing controller twice

AngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

 

The Challenge:

We have an Angularjs application. For this challenge we are going to show only the fragment of code necessary to solve the challenge. Below we have the controller, the view and the router. when you navigate to the #/dashboard page you noticed that the controller is executed twice by placing a breakpoint in your browser console. This makes the analyticsServices.save() method to execute twice duplicating the data in your database. What you would do to prevent angular executing controller twice?

This is the controller

function MyController($scope, userServices, analyticsServices) {

    userServices.get({ id: $scope.currentUserId },
        function(user) {
            analyticsServices.save(user);
        });
}

This is a fragment of the code in the view:

<!-- dashboard.html -->
<div ng-controller="MyController">

<!-- html content -->

</div>

This is the of the router

 .when('/dashboard', {
            templateUrl: '/app/dashboard/dashboard.html',
            controller: 'MyController',
            controllerAs: 'ctr',
            title: 'Dashboard'
});


Solution:

Having the controller defined in the controller property in the router and also defined in the ng-controller in the view, this digested the controller twice. Removing the ng-controller directive from the HTML view can resolve the issue. Alternatively, you can remove the controller: property from the routing directive.


Hope this was helpful, please feel free to leave your comments, share other scenarios, or improve this solution! :)

AngularJs: Notes for a better performance

Performance notes for AngularJs 1.x:

angularjs performanceThis is a compilation of few tips that you can use to improve the performance of your Angular applications. I got some of this techniques from internet and others from my personal experience when working with large enterprise AngularJs applications.

Avoid $watch

-Try to avoid as much as possible the use of $watch because Angular uses dirty checking to keep track of all the changes in app. This means it will have to go through the collection of watcher to check if they need to be updated (call the digest cycle). If one of the watcher is relied upon by another watcher, Angular would have to re-run the digest cycle again, to make sure that all of the changes has propagated. It will continue to do so, until all of the watchers have been updated and app has stabilized.

-One-time binding syntax:

In newer versions of Angular (v1.3.0-beta.10+), use the one-time binding syntax {{ ::value }} where it makes sense

//try to avoid
<div>{{ vm.title }}</div>

// recommended
<hdiv>{{ ::vm.title }}</div>

Binding once removes the watcher from the scope’s $$watchers array after the undefined variable becomes resolved, thus improving performance in each dirty-check. Make sure you use this only when you don’t need to update the value through the application life cycle.

-Debounce the ng-model

If you know there is going to be a lot of changes coming from an ng-model, you can de-bounce the input.
For example if you have a search input like Google, you can de-bounce it by setting the following ng-model option: ng-model-options=”{ debounce: 250 }.
This will ensure that the digest cycle due to the changes in this input model will get triggered no more than once per 250ms. Also you can make the model updates when an event happen, e.g. on blur: ng-model-options=”{ updateOn: ‘blur’ }”
https://docs.angularjs.org/api/ng/directive/ngModelOptions

-Limit DOM filters

Filters are really simple to use, we insert a pipe, the filter name and we’re done. However, Angular runs every single filter twice per $digest cycle once something has changed. This is some pretty heavy lifting. The first run is from the $$watchers detecting any changes, the second run is to see if there are further changes that need updated values.
Here’s an example of a DOM filter, these are the slowest type of filter, preprocessing our data would be much faster. If you can, avoid the inline filter syntax.

{{ filter_expression | filter : expression : comparator }}

Angular includes a $filter provider, which you can use to run filters in your JavaScript before parsing into the DOM. This will preprocess our data before sending it to the View, which avoids the step of parsing the DOM.

$filter('filter')(array, expression, comparator);

 

-Avoid JavaScript expensive operations

The most expensive operation in JavaScript is add or remove elements from the DOM, maybe you wont notice a performance issue when you add or remove a few element, but it could be a problem if you have to remove or insert thousands in a large application.

-How to detect bad performance in AngularJs:

  • Benchmark functions using console.time. You can use the console.time to have a rough idea of how long a function takes to execute the code, you can read more about console.time here.
  • Use Batarang extension to detect performance issues, also you can us it to debug your Angular app in general.

 


 

Tips and good practices in general:

  • Design your directives with Angular in mind, try to avoid as much as possible the use of JQuery.
  • Everything related to DOM manipulation should be in a directive.
  • Avoid use the controller to do business logic, the purpose of controllers is binding data to your view. They should not contain any logic and merely communicate with your services.
  • Use services and /or factories to do business logic and call the Apis.
  • If possible, you should consider fetching your data before your view gets initialized. By doing so, you can ensure that necessary data is available as soon as the user get’s the page, you could accomplish that by using resolve in your routingProvider. See this article.
  • Extend directives by using Directive Controllers, you can place methods and properties into a directive-controller, and access that same controller from other directives. You can even override methods and properties through this relationship.
  • Don’t wrap element inside of $(). All AngularJS elements are already jq-objects.
  • Don’t do if (!$scope.$$phase) $scope.$apply(), it means your $scope.$apply() isn’t high enough in the call stack. Best Practice to run the cycle digest
  • Don’t create a new plugin without trying to discover, fork and pull request existing plugins first.

Prevent flicker when Angular route change until model gets loaded (Mini-Challenge 10) Answer

Check out Mini-challenge 10 Instructions

Answer:route

The $routeProvider service’s resolve property allows delaying of route change until data is loaded.

First define a route with resolve attribute like this.

angular.module('myApp', ['myAppFilters', 'myAppServices', 'myAppDirectives']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/users', {
        templateUrl: 'partials/user-list.html', 
        controller: userListCtrl, 
        resolve: userListCtrl.resolve}).
      when('/users/:userId', {
        templateUrl: 'partials/user-detail.html', 
        controller: userDetailCtrl, 
        resolve: userDetailCtrl.resolve}).
      otherwise({redirectTo: '/users'});
}]);

Notice that the resolve property is defined on the route.

function userListCtrl($scope, users) {
  $scope.users = users;
}

userListCtrl.resolve = {
  users: function(user, $q) {
    var deferred = $q.defer();
    user.query(function(successData) {
            deferred.resolve(successData); 
    }, function(errorData) {
            deferred.reject(); 
    });
    return deferred.promise;
  },
  delay: function($q, $defer) {
    var delay = $q.defer();
    $defer(delay.resolve, 1000);
    return delay.promise;
  }
}

 

Notice that the controller definition contains a resolve object which declares users prop which should be available to the controller constructor and gets injected as dependency and it is defined in the resolve property.

The resolve.users function is responsible for returning a promise. All of the promises are collected and the route change is delayed until after all of the promises are resolved, in this example we are delaying the promise to better illustrate the example.

 

References:

https://docs.angularjs.org/api/ngRoute/provider/$routeProvider

If you have a solution for this challenge, different from the proposal solution on this post, don’t be shy and share it with us :)

Prevent flicker when Angular route change until model gets loaded (Mini-Challenge 10)

Mini-Challenge 10

ng-challenge modelAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

 

The Challenge:

Sometimes it happen that when you navigate from one route to another, and you are using services to call apis and fetch the model, the html view gets loaded first provoking a flick.

This is an example of what we want to achieve with this challenge, if there were a PeopleController that listed all Projects and people.html which is the html template that shows the list of peoples, MyService.PeopleQuery() would be fetched completely before showing the new html page. Until then, the current page would still continue to show.

With the solution that you going to provide for this challenge we also going to prevent that the view show the double curly braces in its raw (uncompiled) form: {{ myVariable }}.
Note:
Notice that using ng-cloak is not the solution, with this directive the HTML is shown, this directive only prevent the view to show the uncompiled angular.
ngCloak Documentation

 

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.

How two controllers can communicate between each other (Mini-Challenge 9) Answer

Check out Mini-challenge 9 Instructions

Answer:

There are several ways that one controllers can talk to another, This google group thread, http://groups.google.com/d/topic/angular/m_mn-8gnNt4/discussion, discusses 5 ways controllers can talk to each other.Controllers Mini-Challenge 9 Answer

1. Shared service.
2. Events.
3. Prudent pragmatic use of $root scope.
4. Watchers.
And a 5th – scope prototypical inheritance?
http://docs.angularjs.org/guide/scope

For a sake of simplicity we are going to show a possible answer to this challenge with Events, using $broadcasting and $on:
This is the view:

<div>
<div ng-controller="Ctrl1">
        <input type="text" ng-model="foo" />
        <input type="button" value="Talk to Ctrl2" ng-click="talkToCtrl2()" />
    </div>
<div ng-controller="Ctrl2">{{foo}}</div>
</div>

And this is the javascript:

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


myApp.controller('Ctrl1', myController);
myController.$inject = ['$scope', '$rootScope']

function myController($scope, $rootScope) {
    $scope.foo = "setted in ctrl1";
    $scope.talkToCtrl2 = function () {
		$rootScope.$broadcast('emitedFromController1', $scope.foo);
    }
};

myApp.controller('Ctrl2', myController2);
myController2.$inject = ['$scope']

function myController2($scope) {
    $scope.foo = "setted in ctrl2";
     $scope.$on('emitedFromController1', function(event, args) {
     	$scope.foo = args;
     });

};

In the talkToCtrl2 function we can implement $rootScope.$broadcast(’emitedFromController1′, $scope.foo); and then in the second controller we can implement:
$scope.$on(’emitedFromController1′, function(event, args) {
$scope.foo = args;
});

You can see a working example in this jsFiddle:

If you have a solution for this challenge, different from the proposed solution on this post, don’t be shy and share it with us :)

How two controllers can communicate between each other (Mini-Challenge 9)

Mini-Challenge 9

ng-challenge controllersAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

I have two controllers in an AngularJs application, I need to make a change to a variable in one controller and click a button that will going to talk to the second controller, lets suppose we have this in the View:

<div>
<div ng-controller="Ctrl1">
        <input type="text" ng-model="foo" />
        <input type="button" value="Talk to Ctrl2" ng-click="talkToCtrl2()" />
    </div>
<div ng-controller="Ctrl2">{{foo}}</div>
</div>

 

And then we have this in the controllers:

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

myApp.controller('Ctrl1', myController);

myController.$inject = ['$scope']

function myController($scope) {
$scope.foo = "setted in ctrl1";
$scope.talkToCtrl2 = function () {
//Implement this function
}
};

myApp.controller('Ctrl2', myController2);

myController2.$inject = ['$scope']

function myController2($scope) {
$scope.foo = "setted in ctrl2";

};

The challenge for you is to implement the talkToCtrl2() function, so when you click the button the data in the input text get passed to Ctrl2 and gets printed in the view.
Here is a working example in jsFiddle:

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.

angular set focus on input field (Mini-Challenge 8) Answer

Check out Mini-challenge 8 Instructions (angular set focus)

Answer:

The Angular way to set the focus to an element inside a modal, is with a directive (since this is related to the DOM and Events).

When a Modal is opened, set focus on a predefined <input> inside this Modal.angular set focus
Define a directive and have it $watch a property/trigger so it knows when to focus the element:

Name: <input type="text" focus-me="isOpen">

 

app.directive('focusMe', function($timeout, $parse) {
  return {
    //scope: true,   // optionally create a child scope
    link: function(scope, element, attrs) {
      var model = $parse(attrs.focusMe);
      scope.$watch(model, function(value) {
        if(value === true) { 
          $timeout(function() {
            element[0].focus(); 
          });
        }
      });
      // on blur event:
      element.bind('blur', function() {
         scope.$apply(model.assign(scope, false));
      });
    }
  };
});

Notice that we also added a code for when the element loose the focus (blur) it sets the isOpen property back to false.

Here is a working example:
http://jsfiddle.net/7L8vqf8u/3/

Recommendations:

It is highly recommended try to avoid as much as possible the use of the $watch service. This is another possible solution using angular events:

app.directive('focusOn', function($timeout) {
   return function(scope, element, attrs) {
      scope.$on(attr.focusOn, function(e) {
          $timeout(function() {
            element[0].focus(); 
          });
      });
   };
});

 

Now you can put your directive in the view:

<input type="text" focus-on="isOpen" />

 

and then, in your controller:

$scope.open = function () {
    $scope.$broadcast('isOpen');
};

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

If you have a better solution on how angular set focus, for this challenge, different from the proposed solution on this post, don’t be shy and share it with us :) you can leave a message on this blog or you can twit me @JoMendezdev.

Focus on input field in AngularJS (Mini-Challenge 8)

Mini-Challenge 8

ng-challengeAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

What is the ‘Angular way’ to set focus on input field in AngularJS?

More specific requirements:

  1. When a Modal pop-up is opened, set focus on a predefined <input> inside this Modal.

I tried to achieve the first requirement with autofocus, but this works only when the Modal is opened for the first time, and only in certain browsers (e.g. in Firefox it doesn’t work). What would be and elegant way to solve this problem?

 

HTM Code:

<div ng-controller="ModalController">
    <button class="btn" ng-click="open()">Click to Open Modal </button>
<div modal="isOpen" close="close()">
<div class="modal-header">
<h4>Modal</h4>
        </div>
<div class="modal-body">
            Name: <input type="text" autofocus>
        </div>
<div class="modal-footer">
 <button class="btn btn-warning cancel" ng-click="close()">Cancel</button>
        </div>
    </div>
</div>

 

Here you can find a working example:

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.