Angular custom directive with promise not working - javascript

I'm trying to build a directive based on Angular custom filter with promise inside. I tried defining a filter, with the same result.
The issue is that I always get {} as the value, whenever I use a promise.
The following simple example shows the issue very clearly.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
app.directive('convert', ['$q', function ($q) {
return {
template: '{{convertFunc()}}',
link: function (scope, elem, attrs) {
scope.convertFunc = function () {
var def = $q.defer();
def.resolve('test');
return def.promise.then(function (s) {
return s; // debugger doesn't stop here
}, function (e) {
return e; // debugger doesn't stop here
});
};
}
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.28/angular.js" data-semver="1.2.28"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div data-convert></div>
</body>
</html>
Can you help finding out what am I doing wrong?
Edit
This is the plnkr I used to create the example.
Edit 2
I'm trying to show the result of the promise on a page. In my real code I'm calling a service and then building a string using values from the service.
VS debugger shows that my string is built correctly. But I cannot display it on the page. I'm under the impression, that JS/Angular fails to recognize completion of the promise. I cannot stop on the breakpoints marked above.

Related

How to execute ng-change after loading data on custom directive

I wrote a custom directive in angular js that is available in plnkr,
when the directive is loaded it already calls the changed() function on MainCtrl, I need to stop changed() function until the data loads into the directive and after that, it should start to watch the changes on input which is inside the directive and BTW the changed() function should be in MainCtrl as it is in the example so is there any way to stop execution of ng-change before loading data into directive?
here is the code:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = "someName";
$scope.statusText = "unChanged";
$scope.changed = function(){
$scope.statusText = "changed";
};
});
app.directive("myDirective", function () {
return {
restrict: 'EA',
scope: {
ngModel: "=",
ngChange: "="
},
templateUrl: "template.html",
link: function ($scope, elem, attrs) {
}
}
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<my-directive ng-model="name" ng-change="changed()"></my-directive>
<p>{{statusText}}</p>
<script type="text/ng-template" id="template.html">
<input type="text" ng-model="ngModel" ng-change="ngChange" >
</script>
</body>
</html>
you have to change your directive's receive property ngModel and ngChange, it conflicts with angularhs's built in directives.
use '&' if you want to call function out of directive
refer this plunker(I just forked from your question).

angularjs: can't show the returned value of JS `typeof`

I have a plnkr of a simple code that tries to display the value of typeof("a") in an html page. What I always get is nothing displayed, while I'm expecting for "string". The same goes for other data types. Here is my plnkr:
https://plnkr.co/edit/mUASA8s9TgplwysMhXvG?p=preview
Am I missing something?
I'll note that my final goal is to use ng-if with a condition that is based on the type of a variable.
Angular version: 1.4.8
you not access directly typeof in TEmplate. other approach use this:
In Controller
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.typeOfFun = function(name){
return typeof name;
}
});
In Templte
<div>{{typeOfFun("a")}}</div>
Your code has several problems:
typeof's syntax is typeof a and not typeof(a)
typeof is not a legitimate expression for angular's expression-binding, thus isn't printed to the template.
Considering the two points above, you should move the check to an external function and use the correct syntax - and everything works :)
See the corrected code:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.getTypeOfA = function() {
return typeof "a"
}
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js" type="text/javascript"></script>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div>{{"aaa"}}</div>
<div>{{getTypeOfA()}}</div>
</body>
</html>
Obviously, you would want to pass a variable to the "checkTypeOf" function and return the result and not do it as I did. This is only for demonstration purposes!!!!

AngularJS Directive to include file content

I´m trying to create a directive in AngularJS for a small templating issue. In my HTML-File I have this:
<div myinclude="header.tpl.html"></div>
My directive should transform this to that:
<div>{content of file: header.tpl.html}</div>
This is how far (or not) I´ve come, but I guess, I´m missing a piece:
myApp.directive('myinclude', function () {
return {
compile: function compile( tElement, tAttributes ) {
console.log(tAttributes.myinclude); // logs filename
return {
templateURL: tAttributes.myinclude
};
}
};
});
Has anyone done something like this before, and is willing to share?
Here is the working plunker.
Try something like this:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.setValue = function(ele) {
console.log(ele)
};
});
app.directive("myInclude",function(){
return {
restrict : 'A',
link : function(scope, element, attrs){
scope.getContentUrl = attrs["myInclude"];
},
template: "content of file : {{getContentUrl}}"
}
});
HTML
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div my-include="header.tpl.html"></div>
</body>
</html>
Its working...
app.directive('productDescription',function(){
return {
restrict:'E',
templateUrl: 'product-description.html'
};
});

DI in directive results in unknown somethingProviderProvider

I know that AngularJS appends "Provider" to registered providers, so it is not necesary to name them with that "provider" and you should call them with the full name as "SomethingProvider".
I'm doing that but the console throws me an
Unknown provider: ReportProviderProvider <- ReportProvider <- reportDirective
I have a service, provider and directive called Report, everyone in its own file. ReportProvider.js, ReportService.js, ReportDirective.js
When I try to use the directive I got the error.
Why do angular appends "Provider" to my required dependency?
angular.module('thdmaterialApp')
.provider('Report', function () {});
angular.module('thdmaterialApp')
.service('Report', function (ReportProvider) {
});
angular.module('thdmaterialApp')
.directive('report', function (ReportProvider) {} );
you don't need to write it like this ReportProvider ,, you just need to inject Report ,,
you will have to add Provider when you want to use it in config ,, but in DI it works as other injectable services ,,
and I think of course you will need to change the name of Report service ,,
You are trying to inject a the provider into your directive? I think they are only meant to be used inside config blocks to pre-configure a service. From the docs:
You should use the Provider recipe only when you want to expose an API
for application-wide configuration that must be made before the
application starts. This is usually interesting only for reusable
services whose behavior might need to vary slightly between
applications.
Also, I think your provider will need to define this.$get as a function that returns an object for it to work.
You only need to use provider if you want to be able to change some properties on a service in some situations. I've tried to show this in a DEMO you might find helpful.
app.js
var app = angular.module('thdmaterialApp', []);
app.controller('MainCtrl', function($scope, ReportService, Report) {
$scope.serviceValue = ReportService.value;
$scope.value = Report.getValue();
});
app.provider('Report', function () {
// if you remove the config block you should see this value
this.value = 'default';
this.configureValue = function(newValue){
this.value = newValue;
}
this.$get = function() {
var value = this.value;
return {
getValue: function() {
return value
}
}
};
});
// if you comment this out then the default value will be returned
app.config(function(ReportProvider){
ReportProvider.configureValue('new configured value');
});
app.service('ReportService', function () {
return {
value: 'I don\'t need to be configured.'
};
});
index.html
<!DOCTYPE html>
<html ng-app="thdmaterialApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.3/angular.js" data-semver="1.4.3"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>ReportService.value: {{serviceValue}}</p>
<p>Report.getValue(): {{value}}</p>
</body>
</html>

Element height from within an AngularJS directive

I'm trying to get the height of elements in a simple AngularJS app.
See below. What am I doing wrong? The height should be different as the lines wrap, but I get 20 reported back to me regardless of what I input in the "labels" array.
The following code can be executed here, otherwise see below.
http://js.do/code/49177
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<base href="/">
<title>height of element in angularjs</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.8/angular-route.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
'use strict';
var app = angular.module('heightApp', ['ngRoute', 'routing']);
app.controller('heightCtrl', ['$scope', function ($scope) {
$scope.labels = [
'Hi there, I\'m a div.',
'Me too, I\'m also a div.',
'Can you see me, because I certainly can\'t see myself. I don\'t even know my own height. Isn\'t that just crazy?'
];
}]);
angular.module('routing', []).config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'height.html',
controller: 'heightCtrl'
});
}]);
angular.module('heightApp').directive('reportMyHeight', function() {
return function (scope, el, attrs) {
alert('offsetHeight = ' + el[0].offsetHeight);
}
})
</script>
</head>
<body ng-app="heightApp">
<div class="container">
<div ng-view></div>
</div>
</body>
<script type="text/ng-template" id="height.html">
<div class="row">
<div class="col-sm-4" report-my-height ng-repeat="lbl in labels">
{{ ::lbl }}
</div>
</div>
</script>
</html>
You need to wait till the next digest cycle. When you do it right away in the directive the interpolations {{ ::lbl }} inside the ng-repeat would not have expanded yet. You can place it in a $timeout turning off the applyDigest argument.
i.e, example:
angular.module('heightApp').directive('reportMyHeight', function($timeout) {
return function (scope, el, attrs) {
$timeout(init, false);
//Initialization
function init(){
console.log('offsetHeight = ' + el[0].offsetHeight, el.html());
}
}
});
Plnkr
Another way to make sure you get the height of the element is to use watch.
angular.module('heightApp').directive('reportMyHeight', function($timeout) {
return function (scope, el, attrs) {
scope.$watch('lbl', function(newval, oldval){
alert(newval + '\n\n' + 'offsetHeight = ' + el[0].offsetHeight);
});
}
})
It will only be triggered once since you use ::.

Categories

Resources