The value is never shown on the DOM and i'm just trying to see if this way works..
What i am trying to do is create a new scope value inside the directive and show it to the DOM
app.directive("rest", ["restFactory", function($rest){
return {
restrict: "A",
scope: {
uri: "#rest",
},
link: function(scope){
scope.$rest = [];
$rest.batch(scope.uri)
.then(function(data){
scope.$rest = data;
});
}
}
}]);
the data i am trying to show comes from a function that returns a promise, and with the promise comes the data i want to use in the DOM
the HTML is coded like this:
<div rest="accounts">
<div ng-repeat="data in $rest">
{{data.id}}
</div>
</div>
this is the first directive i ever did.
I made this plunker to explain why your directive doesn't work.
<div rest="accounts">
<!-- You can't access the directive variable $rest from here
The directives variables are only available on it's template. -->
<div ng-repeat="data in $rest">
{{data.id}}
</div>
</div>
This will work:
app.directive("restTwo", function() {
return {
restrict: "A",
scope: {},
// It will work. I put the template in here.
// You can only access the directive variables from it's template
template: '<div ng-repeat="data in $rest">{{data.id}}</div>',
link: function(scope, el, attr) {
console.log(attr.rest); // output = accounts
//data
scope.$rest = [{
'id': 1,
'name': 'John Doe'
}, {
'id': 2,
'name': 'Johana Doe'
}];
console.log(scope.$rest);
}
}
});
I suggest you to make a factory and make your api call's in it like this:
app.factory('myFactory', function($http) {
// GET example
this.get = function(string) {
return $http({
method: 'GET',
url: 'https://api.github.com/search/repositories?q=' + string
});
}
// Your request here
this.yourRequest = function(uri) {
// return $rest.batch(uri);
}
return this;
});
And in your controller:
app.controller('MainCtrl', function($scope, myFactory) {
$scope.myData = [];
myFactory.get('tetris').then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
$scope.myData = response.data.items;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
});
View:
<div ng-repeat="data in myData">
{{data.id}}
</div>
If you REALLY want to use a directive for this (I do not recommend):
Directive:
app.directive("restThree", function() {
return {
restrict: "A",
scope: {
'data': '='
},
link: function(scope, el, attr) {
//console.log(attr.rest); // output = accounts
//data
scope.$rest = [{
'id': 1,
'name': 'John Doe'
}, {
'id': 2,
'name': 'Johana Doe'
}];
scope.data = scope.$rest;
}
}
});
View:
<div rest-three="accounts" data="directiveData">
<div ng-repeat="data in directiveData">
{{data.id}}
</div>
</div>
Related
I've wrote a directive that should emulate the AngularJS-DataTable.
In this case I need to execute some function on the last <td> since they're buttons. I don't want to pass the functions to the directive to keep the directive as independet as possible.
So in this case, when I specify "renderable" on a data, and a "render" function, if it got a ng-click I need that function, defined in the controller, to be executed, but when i Click on the buttons, nothing happens.
This is the data I've in my Controller, with the function "print()" that I need to call from the directive
$scope.print = function(){
console.log("It worked!");
};
$scope.tableData = {
data: data.response,
columns: [{
title:"",
data: "priority",
renderable: true,
render: function(data){
return "<span class='btn btn-xs fa fa-fw fa-angle-down' ng-click='lowerPriority()'></span>";
}
},
{
title: "Nome Servizio",
data: "title"
},
{
title: "Descrizione",
data: "description",
renderable: true,
render: function(data, row){
var html = "<div ng-click='print()'>"+row.sum+"</div>";
return html;
}
},
],
}
In my page I'm calling
<smart-table data="tableData" ></smart-table>
And then in my directive template
<tr ng-repeat="row in data.data | filter: search.value" repeat-done>
<td ng-repeat="cell in data.columns">
<span ng-if="cell.renderable" ng-bind-html="trustHtml(cell.render(row[cell.data], row))"></span>
<span ng-if="!cell.renderable">{{row[cell.data]}}</span>
</td>
</tr>
Lastly, this is my directive
var smartTable = angular.module('smartTable', ['ngSanitize']);
smartTable.directive('smartTable',['$compile', '$sce', '$templateRequest', function($compile, $sce, $templateRequest) {
return {
restrict: 'AE',
replace: true,
templateUrl: '/public/components/directives/smartTable.tpl.html',
link: function(scope, elem, attrs, parentScope) {
scope.trustHtml = function(data){
var template = angular.element(data);
elem.append(template);
// $compile(angular.element(data))(scope);
return $sce.trustAsHtml(data);
};
$templateRequest('/public/components/directives/smartTable.tpl.html').then(function(html){
console.log(scope);
scope.$watch(attrs.data, function(elemasd) {
var template = angular.element(html);
elem.append(template);
elem.html(html);
scope.data = scope[attrs.data];
$compile(elem)(scope);
});
});
}
};
}]);
Ater your template slightly to use $last, if you're looking for the last td:
<td ng-if="$last" ng-click="vm.print()"></td>
Do something like this bind your function
smartTable.directive('smartTable',['$compile', '$sce', '$templateRequest', function($compile, $sce, $templateRequest) {
return {
restrict: 'AE',
replace: true,
scope: {data: '=',
print: '&'},
templateUrl: '/public/components/directives/smartTable.tpl.html',
link: function(scope, elem, attrs, parentScope) {
scope.trustHtml = function(data){
var template = angular.element(data);
elem.append(template);
// $compile(angular.element(data))(scope);
return $sce.trustAsHtml(data);
};
$templateRequest('/public/components/directives/smartTable.tpl.html').then(function(html){
console.log(scope);
scope.$watch(attrs.data, function(elemasd) {
var template = angular.element(html);
elem.append(template);
elem.html(html);
scope.data = scope[attrs.data];
$compile(elem)(scope);
});
});
}
};
}]);
HTML
<smart-table data="tableData" print="print"></smart-table>
I have a little SPA using angular. The concept is simple, after login, $routeProvider redirects to a home page where I have a homeController specified.
this is from my home view that is rendered by ng-view while navigating to "/home" :
<my-directive datas=getData()></my-directive>
<ul>
<li ng-repeat="data in datas"> {{data.title}} {{data.content}} </li>
</ul>
my directive is written as:
angular.module('app').directive('myDirective', ['myService', function (myService) {
return {
restrict: "E",
scope: {
data: '='
},
templateUrl: "partials/my-directive.html",
controller: function ($scope) {
$scope.getDatas = function()
{
myService.retData();
}
}
};
}]);
the home controller is:
angular.module('app').controller('homeController', homeController);
homeController.$inject = ['myService', '$scope'];
function homeController(myService, $scope) {
var vm = this;
vm.data = [];
initController();
function initController() {
vm.data = myService.retData();
}
}
and finally my service is
angular.module('app').service('myService', myService);
function myService () {
var data = [
{ id: 1, title: 'Albert Einstein', content: 'Random Content' }
];
return {
retData: function () {
return data;
},
addData: function (title, content) {
var currentIndex = data.length + 1;
data.push({
id: currentIndex,
title: title,
content: content
});
}
};
}
now that i mentioned everything, here comes the problem. the directive is not able to retrieve data from the service. Actually when i run the project in VS2013, myDirective.js is not even loaded. I included all services, directives, controllers etc in the main HTML page.
What is causing this problem?
Does it have something to do with the scope being isolated in the directive?
What is a better approach to sharing data between a controller, directive and service?
I may have made some silly mistakes while rewriting all the code. Please do point them out, however keep in mind my actual issue and what error may be causing that.
Better to use isolated scope to pass data controller to directive.
Html:
<my-directive datas="getData()" data="data"></my-directive>
Directive:
angular.module('app').directive('myDirective', [function () {
return {
restrict: "E",
scope: {
data: '='
},
templateUrl: "partials/my-directive.html",
link: function (scope) {
//Here you got the isolated scope data
var details = scope.data;
}
};
}]);
OR
app.directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: 'partials/my-directive.html',
scope: {
date: '=',
},
controller : ['$scope', 'myService', function($scope, myService) {
myService.retData();
}],
link: function(scope, elem, attr) {
//
}
};
});
Here i want to pass $scope.myData of app.js to the directive mcsaForm and use the object attributes in myTemplate.html. My code is working properly except the approach which i mentioned above.
app.js
myApp.controller("myCont", function($scope){
.
some code
.
.
$scope.getTypeOfEvent = function(typeOfEvent, idOfEvent)
{
if(typeOfEvent == "MCQ")
{
if(idOfEvent)
{
var indexOfEvent =$scope.namesTwo.Events.indexOf("idOfEvent")+1;
var valueAtIndex = $scope.namesTwo.Events[indexOfEvent].id;
$scope.myData = $scope.namesTwo[valueAtIndex];
console.log($scope.myData); // output: Object {eventId: "001", TimeOfEvent: "2", EventType: "MCQ"}
}
//fetchJsonDir.gettingContData;
$scope.mCSSQ(typeOfEvent,idOfEvent);
}
}
});
myDirective.js
videoCourseApp.directive("mcsaForm",['fetchJsonDir', function(fetchJsonDir){
return{
restrict: "C",
templateUrl: "assets/template_blocks/Preview_forms/myTemplate.html",
scope: {
myData: "="
},
compile: function(scope, element, attrs)
{
$("#mcss_option_list").append("Hello");
},
controller: function($scope){
$scope.onSubmitHidePanel = function()
{
$(".mcsa_form").fadeOut("slow", function(){
$(this).remove();
});-
}
}
}
}]);
myTemplate.html
<div id=mcss_option_list>
</div>
<div>
001, 2, MCQ//print myData.eventId, myData.TimeOfEvent or whatever..
</div>
Use your directive like
<div class="mcsa-form" my-data="myData"></div>
You will get the value in your directive's myTemplate.html
<div id=mcss_option_list>
{{myData.TimeOfEvent}}
</div>
I'm a bit stuck on an directive which add attributes and recompile the element.
If I had a scope on the directive ng-change is not triggered anymore (without it it works). I based my test on this answer
The HTML
<div ng-app="myApp">
<div ng-controller='testController'>
<div ng-repeat="field in fields">
<input type="text" ng-model="ngModel[field.fieldName]" property="{{formParams.getProperties(field.fieldName)}}" update-attr ng-change="test()" />
</div>
</div>
</div>
The directive:
angular.module('myApp', [])
.controller('testController', function ($scope) {
$scope.properties = {
"something": {
"style": "float:left;"
},
"something2": {
"style": "float:right;"
}
};
$scope.ngModel = {};
$scope.fields = [{
fieldName: 'something'
}, {
fieldName: 'something2'
}];
$scope.test = function () {
alert('i dont get triggered');
};
$scope.formParams = {
getProperties: function (fieldName) {
return $scope.properties[fieldName];
}
};
})
.directive('updateAttr', function ($compile) {
return {
restrict: 'A',
replace: true,
terminate: true,
scope: {
ngModel : '='
},
link: function (scope, elem, attrs) {
if (angular.isDefined(attrs['property']) && attrs['property'].lenght != 0) {
var json = JSON.parse(attrs['property']);
angular.forEach(json, function (value, key) {
elem.attr(key, value);
});
elem.removeAttr('property');
var $e = $compile(elem[0].outerHTML)(scope);
elem.replaceWith($e);
}
}
};
});
Here a fork of the fiddle to test with a scope on the directive: fiddle
Do you have any suggestion ?
I found why ng-change was not trigger so I share the answer:
When we add scope attribute on the directive, a new scope is created. So we have to use $scope.$parent for the compilation. I have updated the fiddle with the correction.
If there is a directive defined can the scope passed to it through attributes, defined on it, be used inside this directive to get needed results for usage in template? i.e. I have such directive
var carAuction = angular.module('carAuction');
carAuction
.controller('mainCtrl', function($scope)
{
var car = {
comments: []
};
car.comments.push({
comment: 'Ok car',
rating: 1
});
car.comments.push({
comment: 'Nice car.',
rating: 2
});
car.comments.push({
comment: 'Awesome car!',
rating: 3
});
$scope.car = car;
})
.directive('carCommentRaiting', function()
{
return
{
restrict: 'E',
templateUrl: 'path/to/template.html',
scope:
{
value: '=value',
maxValue: '=max-value'
}
};
})
.filter('range', function()
{
return function(input, total)
{
total = parseInt(total);
for (var i=1; i<=total; i++)
{
input.push(i);
}
return input;
};
});
In html part I have
<div>
<div ng-repeat="comment in car.comments">
Rating: <car-comment-raiting value="comment.rating" max-value="10"></car-comment-raiting>
</div>
</div>
template.html
<div>
<ul class="list-inline">
<li ng-repeat="n in [] | range:value"><span class="glyphicon glyphicon-star"></span></li>
</ul>
</div>
And I want to pass additional value to the template which should be calculated as maxValue - value. Haven't found any example describing that. Thought about using link property, but description tells, that it is used for other purpose.
UPD:
I was able to fix it with
return {
restrict: 'E',
templateUrl: 'path/to/template.html',
scope:
{
value: '=',
maxValue: '='
},
controller: function($scope)
{
$scope.calculated = $scope.maxValue - $scope.value;
}
};
but for some reason it doesn't work all the time. One time it works and the other time calculated variable is null.
All calculations must be done inside a direcitve link function or in controller.
Here is example with directive:
.directive('carCommentRaiting', function() {
return {
restrict: 'E',
template: 'path/to/template.html',
scope: {
value: '=value',
maxValue: '=max-value'
},
link : function(scope, element, attr) {
scope.calculated = scope.maxValue - scope.value;
/// watch value to update calculated on value update:
scope.$watch('value', function(newValue){
scope.calculated = scope.maxValue - newValue;
});
}
};
});