Beginner questions with AngularJS and directives - wrapping a jQuery component

First, I should mention I am just working on transitioning to clientside programming. I am very new to js. My previous experience is primarily in C and some assembly. I also did a bit of very simple php years ago when it was still 4.0. So in short, new to javascript but putting my head around it a bit.

I have done quite a bit of searching and lurking but have not been able to rectify my issues.

I am figuring out some of the basics of AngularJS and it is quite nice, but I am having difficulty wrapping my head around how directives work and how to access data from custom controls.

Long story short I am trying to make a custom control for bootstrap work with angularjs so I can use it in forms properly.

Here is the control: http://tarruda.github.com/bootstrap-datetimepicker/

I have some other controls that I want to make work but I figure if I can get this one going I can probably get the others easily enough.

Here is a link to a basic framework what I have at this point: http://jsfiddle.net/uwC9k/6/

First off, I am trying to wrap my head around how to initialize the control once I have the template working (Which, I pretty much do at this point I think)

link: function(scope, element, attr) {
            attr.$observe('dpid', function(value) {
                if(value) {
              $('#' + scope.dpid).datetimepicker({
                  language: 'en',
                  pick12HourFormat: true
            });
}

When I put that in the link directive, it does nothing. I don't even see any errors. scope.dpid is indeed showing the ID of the control so I thought it would work. But alas, my febble understanding of javascript tells me that I am outside of the scope or some such nonsense where I cannot access the element.

Once I get that going, I am not exactly sure how to make this data accessible in forms either.

Any help is greatly appreciated.

Update Got the basic bit working, now I need to know how to get the data from the new control into my controller. Here is a link to the new jsfiddle updated. http://jsfiddle.net/tmZDY/1/

Update 2 I think I have an idea on how to make this data accessible but my lacking knowledge of javascript has left me dry again.

when I create the object I do it thusly.

var elDatepicker = element.datetimepicker({
language : 'en',
pick12HourFormat : true,
});

However, when I try to use this object it does not seem to be getting the correct one, or I am just missing some basic knowledge. Either way this is sure making me feel foolish.

console.log(elDatepicker.getDate());

This fails, getDate is indeed a method, at least it looks like it is in the code of the plugin.

Instead of an isolate scope, you can find() the first div of your template and then apply datetimepicker(). So you don't need an id in your HTML:

<datepicker model="mydate"></datepicker>
mydate = {{mydate}}

I also suggest replace: true:

.directive('datepicker', function ($parse) {
    return {
        restrict: 'E',
        replace: true,
        template: '<div class=\"well\"><div class=\"input-append\">'
         + '<input data-format=\"MM/dd/yyyy HH:mm:ss PP\" type=\"text\"></input>'
         + '<span class=\"add-on\"><i data-time-icon=\"icon-time\" data-date-icon=\"icon-calendar\"></i></span>'
         + '</div></div>',
        link: function (scope, element, attr) {
            var picker = element.find('div').datetimepicker({
                language: 'en',
                pick12HourFormat: true
            });
            var model = $parse(attrs.model);
            picker.on('changeDate', function(e) {
               console.log(e.date.toString());
               console.log(e.localDate.toString());
               model.assign(scope, e.date.toString());
               scope.$apply();
           });
        }
    };
})

Fiddle

$parse is a bit tricky. What I show is the main use case for it: we parse an attribute and get back a function which has an assign() method on it that allows us to change the scope property.

One of the way to do may be this, as shown in this fiddle. http://jsfiddle.net/uwC9k/10/

As the datepicker element has to be replaced with the template string, this will be a good use case to use the compile function. So inside the compile function im replacing the datepicker element with the template string.

Once the compling is done, we will go to the link function, which is nothing but the function returned from inside the compile function. What the linking function will do is to initialize this <div class=\"input-append\"> element with date picker functionality using

element.datetimepicker({
                      language: 'en',
                      pick12HourFormat: true
                });

Since you are including the jquery, the element attribute in the linking function is a jquery warpped element. So you can straight away call the datetimepicker method.

You can add a class like datetimepicker to the div which has to be converted to the datetimepicker, then use that class to look up for the element.

.directive('datepicker', function() {
    return {
        restrict: 'E',
        template: '<div class=\"well\"><div id={{dpid}} class=\"input-append datetimepicker\"><input data-format=\"MM/dd/yyyy HH:mm:ss PP\" type=\"text\"></input>    <span class=\"add-on\"><i data-time-icon=\"icon-time\" data-date-icon=\"icon-calendar\">      </i>    </span>  </div></div>',
        scope: { dpid: '@'},
        link: function(scope, element, attr) {
            attr.$observe('dpid', function(value) {
                if(value) {
              $(element).find('.datetimepicker').datetimepicker({
                  language: 'en',
                  pick12HourFormat: true
            });
                }
            });
        }
    };
})

Demo: Fiddle