0

OK so I am trying to make a simple chat widget directive and I want it to be dynamically created wherever I want it on my app ie I do not want a hard coded solution. So I want the directive to be created from a service and therefore have its scope variables set via service helper methods. I think I see a few examples of this in some angularjs material directives for example I want to do something like:

$mdToast.simple()
  .textContent('Marked as read')
  .action('UNDO')

but instead my chat widget will be like:

$chatWidget.setParent(parent).setUser(user).setMessages(messages);

Here is an extremely simplified version of the directive so far:

        angular
    .module('app')
    .directive('reChat', function ($chatWidget) {
        return {
            restrict: 'E',
            replace: true,
            template: 

    '<div id="chat-widget-container"><div id="chat-widget-header">User.name</div>'+
    '<div id="chat-widget-body"<div ng-repeat="message in reMessages"><div>' +
    '<p> {{message.body}} </p></div></div></div>' +
      '<textarea ng-model="messageToSend" id="message-to-send" placeholder ="Type your message" rows="3"></textarea>' +
      '<button class="btn btn-default" ng-click="sendMessage()">Send</button></div>'

,
            scope: {
                reMessages: '=',
                reParent: '<',
                reUser: '<'
            },
            link: function (scope, element, attrs) {

                scope.sendMessage = function () {
                    //logic here...
                };
        };
    });

So how do I set the three scope variables in my directive above (reMessages, reParent, reUser) from the following factory?

angular
.module('app')
.factory('$chatWidget', function ($document, $compile, $controller, $http, $rootScope, $q, $timeout) {
        return {
            // functions
        }
    })

Any help greatly appreciated.

  • 1
    There are known, very silly problems with `replace: true`, a number of which can't really be fixed in a reasonable fashion. If you're careful and avoid these problems, then more power to you, but for the benefit of new users, it's easier to just tell them **"this will give you a headache, don't do it".** See [Why is `replace` property deprecated in AngularJS directives?](https://stackoverflow.com/questions/24194972/why-is-replace-property-deprecated-in-angularjs-directives). – georgeawg Feb 19 '18 at 14:41
  • The [$mdToast Service](https://github.com/angular/material/blob/master/src/components/toast/toast.js) builds and adds a toast to the [$rootElement](https://docs.angularjs.org/api/ng/service/$rootElement) or the element specified by the [`parent` option](https://github.com/angular/material/blob/master/src/core/services/interimElement/interimElement.js#L630). – georgeawg Feb 19 '18 at 14:44

1 Answers1

2

In general, to set a directive scope property from a service, simply assign it:

app.directive('reChat', function ($chatWidget) {
    return {
        scope: {
            reMessages: '=',
            reParent: '<',
            reUser: '<'
        },
        link: function (scope, element, attrs) {                
            scope.reMessages=$chatWidget.reMessages;
            //OR asynchronously
            $chatWidget.getReMessages()
              .then(function(reMessages) {
                scope.reMessages = reMessages;
            }).catch(function(error) {
                console.log(error);
            }}; 
        },
   };
})

Since one-way < binding was introduced with V1.5, the AngularJS team recommends that two-way = binding be avoided. For inputs, use one-way < bindings and attribute @ bindings. For outputs, use expression & bindings which function as callbacks to component events. The general rule should be to never change a parent object or array property from the component. This will make transition to Angular 2+ easier.

For more information, see AngularJS Developer Guide - Component-based application architecture.

georgeawg
  • 48,608
  • 13
  • 72
  • 95