14

I'm using a template to create a popup menu that will show alerts if there is a new one and it's working till now. But i wanted to add manual alert, that's why i thought to add an input text but Oupss, i can't write on the input field and i don't even know why.The input field is sort of Disabled!!!

My directive is like so :

$scope.tb = { x: 0, y: 0 };

module.directive('myDraggable', function ($document, $interval) {
return {
    restrict: 'EA',
    replace: true,
    //scope : true,
    scope: { menu: '=drSrc'},
    link: function (scope, element, attr) {

        var startX = 0, startY = 0, x = scope.menu.x || 0, y = scope.menu.y || 0, positionX = [], positionY = [], time = [], width, height, moveInterval;

        element.draggable({
            position: 'relative',
            cursor: 'pointer',
            top: y + 'px',
            left: x + 'px'
        });

        element.on('mousedown', function (event) {

            // Prevent default dragging of selected content
            event.preventDefault();
            startX = event.pageX - x;
            startY = event.pageY - y;
            $document.on('mousemove', mousemove);
            $document.on('mouseup', mouseup);
            $interval.cancel(moveInterval);
        });

        function mousemove(event) {
            y = event.pageY - startY;
            x = event.pageX - startX;
            //calculate the borders of the document 
            width = $(document).width() - 350;
            height = $(document).height() - 150;
            positionX.push(x);
            positionY.push(y);
            time.push(Date.now());
        }
    }
}
 });

I tried to make scope true but i faced 2 problems, : I can't move my popup anymore (yes my popup menu is Draggable) And Also the input text does not show my text i'm typing.

Here's my cache template :

    $templateCache.put('control.tpl.html', '<div class="container" my-draggable dr-src="tb"><div><div class="col-sm-1 col-md-1 sidebar"><div class="list-group" ><span href="#" class="list-group-item active" >Manage<input type="text" class="pull-right" placeholder="Type..." /></span><div ng-repeat="Alert in Alerts"><a href="#" ng-click="showLocation(Alert.id)" class="list-group-item" >Alert {{Alert.id}}</span><img src="../images/alert_icon_manage.png"  class="pull-right"/> </a></div><span href="#" class="list-group-item active"></span></div></div></div></div>');

I'm new with AngularJS and Directive and I don't know how to solve this but I think it's a problem with Scopes!! Thank you.

UPDATE :

If I delete scope:{menu:"=drSrc"} That work and i can type what i want but the problem is that my element is no more draggable. I think it's sth related to scopes. can anyone help please?

Ayyoub
  • 1,315
  • 1
  • 16
  • 37
  • I don't see you input using any model or variable in the scope. Where is its value supposed to be stored? – pfernandom May 08 '15 at 05:00
  • I didn't really understand what you mean ? can you explain more ? – Ayyoub May 11 '15 at 11:16
  • 2
    can you create a plunker or fiddle demonstrating your issue? – Dave Alperovich May 19 '15 at 15:00
  • OKay I'll try to create one and let you know about it – Ayyoub May 19 '15 at 15:28
  • I notice there appears to be some invalid html used in `control.tpl.html` - can you verify that the html demonstrated above is what you're currently using, or have there been some errors introduced in the course of providing the snippet? – JcT May 25 '15 at 10:54
  • In angular docs about directives, they say that: `templateUrl can also be a function which returns the URL of an HTML template to be loaded and used for the directive. Angular will call the templateUrl function with two parameters: the element that the directive was called on, and an attr object associated with that element. **Note: You do not currently have the ability to access scope variables from the templateUrl function, since the template is requested before the scope is initialized.**` could be this the problem? – Alejandro Teixeira Muñoz May 26 '15 at 10:56

2 Answers2

4

scope: true indicates that your directive should inherit its parent's scope, but scope: {menu: '=drSrc'} creates an isolated scope, which remove your template's access to Alerts. When you remove scope: {menu: '=drSrc'}, menu no longer exists, so scope.menu.x fails and your element is no longer draggable.

The simplest fix is to use scope: true and reference scope.drSrc.x, etc. instead of scope.menu.x. With scope: true, you get access to the parent's scope, including drSrc and the Alerts data your template is using.

These writeups are useful in understanding directives and scopes:

Kristján
  • 18,165
  • 5
  • 50
  • 62
  • Exactly right that is the problem but I'm not decalring drSrc anymore if i don't let **scope: {menu:'=drSrc'}** I tried it but in my template cach i'm using the directive **dr-src="tb"** and tb is the variable of my scope where i'm initialising my **x** and **y** it's exactly a problem of accessing my scope what should i put in my html directive ? – Ayyoub May 20 '15 at 08:07
  • Is `tb` always initialized `{x: 0, y: 0}`? If so, why pull it from outside the directive at all? That Plunker @Dave Alperovich asked for would be helpful to see your full case. – Kristján May 20 '15 at 13:38
  • yes it's always initialzed `{x: 0,y:0}`. where i can pull it ? inside the directive ? how can I do that ? I was trying to do it but I had some difficulties and it's not ready yet, I'm still working on it. it's the first time i'm trying to do it and in my project i'm using the google map api and it's not easy for me to do it faster than that. – Ayyoub May 20 '15 at 14:32
  • You'd put it at the top of your link function with the rest of your variables. But you're only using it to initialize `x` and `y`, which you default to `0` anyway, so it looks like you don't need `drSrc`/`menu`/`tb` at all. Just set `x = 0, y = 0` and go from there. – Kristján May 20 '15 at 15:03
  • but my `dr-src="tb"`is the Directive in my HTML that gives the `x`and `y` that means to control the position (top,left) for my draggable popup. – Ayyoub May 20 '15 at 15:46
  • If you're declaring an isolated scope then, you'll need to either pass through everything you want to use (that is, make `alerts` an attribute as well) or reference `scope.$parent` to get to `alerts` from the parent. Here's a [Plunker illustrating both](http://plnkr.co/edit/6pRKUcSrGHiy0taJLT9d) – Kristján May 24 '15 at 19:54
1

I'm currently working on a project that depends heavily upon Modal Dialogs. Each with their own purpose and dynamic content.

Here's the system I have been working with:

index.html

<!doctype html>
<html ng-app="myApp" ng-controller="MainCtrl">
    <head>
        <title>Dialogs</title>
        <link rel="stylesheet" href="app.css">
    </head>
    <body>
        <button ng-click="openDialog()">Open Dialog</button>
        <modal-dialog show="showMe" dialog-controller="WelcomeDialogCtrl" context="welcome"></modal-dialog>

        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
        <script src="app.js"></script>
    </body>
</html>

app.js

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

// The main controller, which will handle index.html
app.controller('MainCtrl', ['$scope', function($scope) {
    $scope.showMe = false;

    $scope.openDialog = function(){
        $scope.showMe = true; // Show the 'welcome' dialog
    };
}]);

// The modal dialog directive
app.directive('modalDialog', [function() {
    return {
        controller: '@', // Bind a controller
        name: 'dialogController', // Bind the controller to this attribute name
        restrict: 'E',
        scope: {
            show: '='
        },
        link: function(scope, element, attrs) {
            // Close this dialog (actually ng-hides it)
            scope.closeDialog = function() {
                scope.show = false;
            };
        },
        templateUrl: function(element, attrs){
            // I prefer to load my dialog templates from a separate folder to keep my project tidy
            return 'dialogs/' + attrs.context + '.html';
        }
  };
}]);

// The 'welcome' dialog has its own controller with its own scope
app.controller('WelcomeDialogCtrl', ['$scope', function($scope){
    // This can be called by the template that resides within the directive
    $scope.exampleFunction = function(text){
        console.log('Example function says: ' + text);
    };
}]);

welcome.html

<div class="dialog" ng-show="show">
    <div class="dialog-overlay"></div>
    <div class="dialog-box">
        Welcome, be sure to check out this blazin' dialog.
        <button ng-click="exampleFunction('Hi!')">Say Hi!</button>
        <button ng-click="closeDialog()">Close</button>
    </div>
</div>

app.css

body{
    background: #eee;
    margin: 80px;
}

/*
 * Just some fancy schmuck
 */
button{
    border-radius: 5px;
    background: #272;
    color: #fff;
    padding: 5px 12px;
    border: 0;
}

/*
 * The grey, transparent curtain.
 */
.dialog-overlay {
    width: 100%;
    height: 100%;
    position: absolute;
    background: #111;
    opacity: 0.2;
    top: 0;
    left: 0;

    z-index: 100;
}

/*
 * The dialog itself. Horribly centered.
 */
.dialog-box{
    background: #fff;
    border-radius: 5px;
    padding: 10px 20px;
    position: absolute;
    width: 600px;
    height: 300px;
    top: 50%;
    left: 50%;
    margin-left: -300px;

    z-index: 110;
}

I also made a Plunker with the same code.

D. Visser
  • 875
  • 2
  • 12
  • 19