Cannot access attribute that is a directive inside another directive's template - angularjs

My custom directive is "testapp". I would like to access the value of "file-model" in its template, which would contain the file object to be uploaded. Whatever I do am not able to get the value, its displaying "undefined". Please suggest ways to solve this problem.
app.directive('testapp', function ($compile) {
return {
restrict: 'E',
scope: {
text: '#',
filem: '=fileModel'
},
require:'fileModel',
replace:true,
template: '<div class="col-xs-4" style="padding-left:0px"><div class ="jumbotron" id="Section1"><input type="text" name="id" id="section{{incr}}" placeholder="Section Heading" class="form-control"><form id="addLIForm1"><div ng-repeat="i in range(fileIncr) track by $index"><input type="text" name="file{{incr}}{{$index+1}}" id="file{{incr}}{{$index+1}}" class="form-control" placeholder="File Name" style="width:50%" ><input type = "file" id="path{{incr}}{{$index+1}}" file-model = "file{{incr}}{{$index+1}}"></div></form><a id="addMore" ng-click="addfile()" href="#">Add More File</a><a id="addMoreSec1" ng-click="add()" class="pull-right" href="#" ng-show="showValue">Add More Section</a></div></div>',
controller: function ($scope, $element,$window) {
$scope.incr=$window.globalIncr;
$scope.fileIncr=$window.globalfileIncr;
$scope.showValue=$window.globalsectionValue;
$scope.add = function () {
$window.globalsectionValue=false;
$window.globalIncr+=1;
$window.globalfileIncr=1;
var el = $compile("<testapp></testapp>")($scope);
$element.parent().append(el);
//alert($window.globalfileIncr);
//alert($element.parent().parent());
};
$scope.range=function(n)
{
return new Array(n);
}
$scope.addfile=function(){
alert($scope.filem);
$scope.fileIncr+=1;
$window.counterObject[$scope.incr] = $scope.fileIncr;
};
}
};
});

Related

Angular.js directive partially not working

I have the following directive:
app.directive('onFileSelected', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element[0]._HANDLE = scope.$eval(attrs.onFileSelected);
element.bind('change', function() {
element[0]._HANDLE();
});
}
};
});
And now, the following html:
<input type="file" name="{{container._id}}" on-file-selected="FileChanged" style="display: block !important;"/>
<div ng-repeat="item in container.items">
<input type="file" name="{{container._id}}" on-file-selected="FileChanged" style="display: block !important;"/>
</div>
In my scope, i have defined the following method:
$scope.container = {
_id: 0,
items: [1,2,3,4,5]
};
$scope.FileChanged = function() {
alert(this.files.length);
};
The Problem is now: This directive works only inside the ng-repeat, but not outside. Any ideas? Am I missing something? Outside of ng-repeat scope.$eval(attrs.onFileSelected); returns undefined.
Thank you!

Adding ng-model to directive

I have the following directive to reverse geocode a lat & long into a place:
/* global app*/
app.directive('reverseGeocode', function () {
return {
restrict: 'A',
template: '<div ng-model="autoLocation"></div>',
link: function (scope, element, attrs) {
var geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(attrs.lat, attrs.lng);
geocoder.geocode({ 'latLng': latlng }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
element.text(results[1].formatted_address);
} else {
element.text('Location not found');
}
} else {
element.text('');
}
});
},
require: "ngModel",
replace: true
}
});
But for some reason, it doesn't seem to retrieve the ng-model and display it:
<div class="form-group move-down" ng-class="{ 'has-error': place === null }">
<label for="place">Picture taken in:</label>
<input type="text" class="form-control" ng-if="!capture.geo" id="place" ng-model="place.formatted_address" ng-autocomplete options="options" required details="place" ng-click="checkPlace(place)"
uib-tooltip="Please pick the location where you captures your photo!"
tooltip-placement="top-right"
tooltip-trigger="mouseenter"
tooltip-enable="!details.formatted_address"
tooltip-class="tooltip">
// DIRECTIVE USED HERE
<reverse-geocode class="form-control" ng-if="capture.geo" lat="{{capture.latitude}}" lng="{{capture.longitude}}">
<div ng-show="place === null" class="noPlace">
<i class="glyphicon glyphicon-remove"></i> Please fill in a valid location!
</div>
</div>
What my goal is, is to display the location below using:
<div ng-if="capture.geo">Place: {{autoLocation}}</div>
First you need to drop restrict or at least use E (element) instead of A (attribute), since you are using the directive as element.
Second, you don't need to add or pass ng-model, which is a directive itself, to your directive. You can access the controller scope variable capture directly. If you prefer directive to have it's own, isolated scope, then you should two-way bind the controller variable to directive's scope using = (or # if you prefer passing literal strings).
If I understood correctly, below is what you are after (simplified but functionality is there).
HTML
<body ng-controller="MyCtrl">
lat <input type="number" ng-model="capture.lat">
lng <input type="number" ng-model="capture.lng">
<reverse-geocode capture="capture"></reverse-geocode>
</body>
JavaScript
angular.module('app', [])
.controller('MyCtrl', function($scope) {
$scope.capture = {
lat: 10.0,
lng: 20.0
};
})
.directive('reverseGeocode', function () {
return {
restrict: 'E',
scope: {
capture: '='
},
template: '<div ng-bind="autoLocation"></div>',
link: function(scope) {
scope.$watch('capture', function() {
if (scope.capture.lat && scope.capture.lng) {
scope.autoLocation = 'reverse geocode address for [' +
scope.capture.lat + ' ' + scope.capture.lng + '] here';
} else {
scope.autoLocation = 'invalid coordinates';
}
}, true);
},
};
});
It won't work in that way. ng-model only works for input type element where a user can pass some input.
You need to use two-way data communication so that you can modify a scope variable from directive to it's associated scope's variable.

KendoUI directive not working after using Angular $compile

I've defined an Angular directive stField (<st-field>). It dynamically creates a DOM element, <st-field-vov>, and inserts it inside using $compile. I need this dynamic injection because there are other types of fields. The DOM would look like this:
<st-field>
<st-field-vov></st-field-vov>
</st-field>
stFieldVov is another custom directive I create, it handles the rendering of the concrete field. Here is the JS:
(function(module) {
'use strict';
module
.directive('stField', _stField)
.directive('stFieldVov', _stFieldVov);
/*ngInject*/
function _stField($compile, stFieldSvc) {
return {
restrict: 'E',
scope: {
stFieldTmpl: '=',
stDataObjects: '='
},
link: function(scope, $elem) {
var _fieldTmpl = scope.stFieldTmpl,
template = '<st-field-' + stFieldSvc.getFieldTypeShortName(_fieldTmpl.type) + '></div>';
$elem.append($compile(template)(scope));
}
};
}
function _stFieldVov() {
return {
restrict: 'E',
link: function(scope) {
var _fieldTmpl = scope.stFieldTmpl,
_dataObjects = scope.stDataObjects,
_isValue = true;
scope.dataObjectDropDownOptions = {
dataSource: new kendo.data.DataSource({
data: _dataObjects
}),
dataTextField: 'name',
dataValueField: 'id'
};
},
templateUrl: '/widgets/fields/directives/templates/vov.html'
};
}
})(angular.module('st.widgets.fields'));
Here is the template for stFieldVov:
<div class="input-group">
<input type="text" class="form-control" ng-show="isValue()">
<input kendo-drop-down-list
k-options="dataObjectDropDownOptions"
k-option-filter="contains">
<span class="input-group-btn">
<button type="button" class="btn"
ng-class="{'st-btn-do': isDataObject()}">
<span class="icon-server"></span>
</button>
</span>
</div>
The problem is that the k-options for configuring the Kendo widget, kendoDropDownList, doesn't work. I think this is because I used $compile to generate <st-field-vov> as k-options works well if use kendoDropDownList in <st-field>.
The browser doesn't throw any error, it is just that the drop down data is empty.
Thanks for reading.
Try to use this:
$elem.append(template);
$compile($elem.contents())(scope);

AngularJS how to bind the ng-model on $watch

I'm building an app using ionic framework and in my search module I'm using a library called ion-autocomplete https://github.com/guylabs/ion-autocomplete trying to bind the ng-model to my scope but I can't get it to bind.
Controller:
$scope.model = "";
$scope.callbackMethod = function (query) {
//scope.model doesn't bind
return PostService.SearchUser($scope.model, $localStorage.CurrentUser.auth_token, -1, -1)
.success(function (data) {
console.log(data);
})
.error(function(error) {
});
};
View:
//this derective is an input field
<ion-autocomplete ng-model="model" items-method="callbackMethod(query)" placeholder="Enter something"/>
Template:
var template = '<input type="search" class="ion-autocomplete-search" ng-model="searchQuery" placeholder="{{placeholder}}"/>'
Directive:
.directive('ionAutocomplete', function () {
return {
require: '?ngModel',
restrict: 'E',
template: '<input ion-autocomplete type="text" readonly="readonly" class="ion-autocomplete" autocomplete="off" />',
replace: true
}
});

Angularjs directive with bi-directional binding not working

I'm trying to write a simple directive that allows the user to edit a certain variable, but when i try to update the parent variable it doesn't work.
this is my html:
<p class="scene-field-name editable-name" editable="foo"> {{foo}} </p>
and the directive:
myApp.directive('editable', function ($window, $compile) {
return {
restrict: "A",
template: '<div class="editable-value" ng-hide="editorOn">{{value}} <a class="edit-a" ng-click="editorOn = true">edit</a></div>' +
'<div class="editable-editor" ng-show="editorOn">' +
'<input type="text" value="{{tmpValue}}" />' +
'<a ng-click="setValue()">OK</a>' +
'</div>',
scope: {
value: "=editable"
},
controller: function($scope) {
$scope.tmpValue = $scope.value;
$scope.editorOn = false;
$scope.setValue = function () {
$scope.value = $scope.tmpValue;
$scope.editorOn = false;
}
}
};
here it is in jsfiddle:
http://jsfiddle.net/4srx2z0c/2/
you can see that when clicking OK it doesn't save the value back in the parent scope...
You don't bind the input to tmpValue.
Instead of <input type="text" value="{{tmpValue}}" /> you should have <input type="text" ng-model="tmpValue" />.

Resources