I have 2 directives in one page. The first one works fine, but the second one not working.
This is my Code:
HTML
<body class="login" ng-app="Login">
<div ng-controller="HttpLoginController">
<wrongdetails></wrongdetails>
<loading></loading>
<input type="submit" ng-click="LoginUser()" value="Login" />
</div>
</body>
JS
var app = angular.module("Login", [])
app.controller("HttpLoginController", function($scope,$http){
$scope.LoginUser = function(){
$scope.loading = true;
var data = [];
var config = {}
$http.post('Mylink', data, config)
.success(function (data, status, headers, config) { $scope.loading = false;})
.error(function (data, status, header, config) {$scope.wrongdetails = true; });
};
});
//Directives
app.directive('loading', function () {
return {
restrict: 'E',
//replace:true,
template: '<div id="loading"> <div class="progress-line"></div><br/> </div>',
link: function (scope, element, attr) {
scope.$watch('loading', function (val) {
if (val)
$(element).show();
else
$(element).hide();
});
}
}
})
app.directive('wrongdetails', function () {
return {
restrict: 'E',
replace:true,
template: '<div class="alert alert-danger display-hide"><button class="close" data-close="alert"></button><span> Error. </span></div>',
link: function (scope, element, attr) {
scope.$watch('wrongdetails', function (val) {
if (val)
$(element).show();
else
$(element).hide();
});
}
}
})
But The second Directive never show.
What I am doing wrong?
Sorry for my mistake. I forget to copy paste the directives.
I think now is ok
Remove the following line in your second directive:-
replace:true ,
The reason with the explanation is already available. Refer this link Explain replace=true in Angular Directives (Deprecated)
Related
I have a directive in my module. And I want to change the templateUrl based on a attribute.
HTML
<div test stage="dynamicstage"></div>
Module
angular.module('trial', [])
.controller('trialCtrl', function ($scope) {
$scope.dynamicstage = 'Welcome';
})
.directive('test', function () {
return {
restrict: 'A',
scope: {
'stage': '='
},
link: function (scope, element, attrs) {
scope.$watch('stage', function(condition){
if(stage === 'welcome'){
templateUrl: "hello.html";
}else{
different template url...
};
});
}
}
});
This does not work. The templateurl is not loaded into the div. I want to change the templateUrl dynamically is this possible.
I appreciate any help.
This is not very transparent in Angular. templateUrl can be a function to dynamically construct template URL, however in your case you need a scope, which is not yet available at the moment URL is constructed.
You can do something like this with the help of ngInclude:
app.directive('test', function() {
return {
restrict: 'A',
scope: {
'stage': '='
},
template: '<div ng-include="templateUrl"></div>',
link: function(scope, element, attrs) {
scope.$watch('stage', function(condition) {
if (scope.stage === 'Welcome') {
scope.templateUrl = "hello.html";
} else {
scope.templateUrl = "other.html";
};
});
}
}
});
Demo: http://plnkr.co/edit/l1IysXubJvMPTIphqPvn?p=preview
Solution1 :
scope.$watch('stage', function(condition){
var templateUrl;
if(stage === 'welcome'){
templateUrl = "hello.html";
} else{
templateUrl = "someothertemplate.html";
};
//load the template;
$http.get(templateUrl)
.then(function (response) {
// template is loaded.
// add it and compile it.
angular.element(element).html(response.data);
$compile(element.contents())(scope);
});
});
Solution2:
Use ng-include
<div test stage="dynamicstage">
<div ng-include="templateUrl"></div>
</div>
Inside directive:
scope.$watch('stage', function(condition){
var templateUrl;
if(stage === 'welcome'){
templateUrl = "hello.html";
} else{
templateUrl = "someothertemplate.html";
};
scope.$parent.templateUrl = templateUrl; // make sure that templateUrl is updated in proper scope
})
I am using Angular-ui to pop up a modal with a form in it. My code is:
app.controller('NewCaseModalCtrl', ['$http', '$scope','$modal', function ($http, $scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'modal-new-case.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
});
};
}]);
And then I have another controller that is inside the modal-new-case.html template, and I want it to run an httpd request and then close that modal, here is that code:
app.controller('CreateCaseFormCtrl', ['$http','$scope', function($http,$scope) {
$scope.formData = {};
$scope.processForm = function() {
$http.post('http://api.com/proj', $scope.formData).
success(function(data, status, headers, config) {
console.log("success " + data.id);
}).
error(function(data, status, headers, config) {
console.log("Error " + status + data);
});
};
}]);
Okay so inside my modal-new-case.html template, which is loaded when I do:
ng-controller="NewCaseModalCtrl"
I have this HTML:
<div ng-controller="CreateCaseFormCtrl">
<form ng-submit="processForm()">
<button class="btn btn-primary" ng-click="processForm()" >OK</button>
<button class="btn" ng-click="cancel()">Cancel</button>
</form>
</div>
So if you see, what I really want to do is to run that processForm() function, and when it returns with a success, I want to THEN call the function that will close the modal, which I believe "cancel()" would be fine.
But I don't know how to refer to it from the CreateCaseFormCtrl controller.
I appreciate any thoughts and help, and I would like to add that I am very unsophisticated when it comes to Angular, so if this is complicated, please remember that maybe I am not 100% clear on what every single thing in Angular is such as the factories and such. I guess I'm saying I'm very happy with a dirty solution that's fairly simple, since this isn't going to be long-term production programming code.
Step 1: remove the
ng-controller="CreateCaseFormCtrl"
from
<div ng-controller="CreateCaseFormCtrl">
<form ng-submit="processForm()">
<button class="btn btn-primary" ng-click="processForm()" >OK</button>
<button class="btn" ng-click="cancel()">Cancel</button>
</form>
</div>
Step 2: Change
controller: 'ModalInstanceCtrl', => controller: 'CreateCaseFormCtrl'
in
var modalInstance = $modal.open({
templateUrl: 'modal-new-case.html',
controller: 'CreateCaseFormCtrl', //Add here
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
Step 3: In CreateCaseFormCtrl add a service called $modalInstance
app.controller('CreateCaseFormCtrl', ['$http','$scope', '$modalInstance', function($http,$scope, $modalInstance) {
Step 4: Add the close and ok functions
$scope.cancel = function () {
$modalInstance.dismiss();
};
and $modalInstance.close(); in
$http.post('http://api.com/proj', $scope.formData).
success(function(data, status, headers, config) {
console.log("success " + data.id);
$modalInstance.close(); //add here
}).
error(function(data, status, headers, config) {
console.log("Error " + status + data);
});
use $modalInstance.dismiss API
in NewCaseModalCtrl:
controller('NewCaseModalCtrl', ['$scope', '$modalInstance', function ($scope, $modalInstance,
...
$modalInstance.close(data);
You an do it globally like this or from other controllers too:
//hide any open $mdDialog modals
angular.element('.modal-dialog').hide();
//hide any open bootstrap modals
angular.element('.inmodal').hide();
//hide any sweet alert modals
angular.element('.sweet-alert').hide();
I have an angular directive that loads data from service,
BUT
it loads the data with a variable he go from a controller that it was loaded as well from a service.
code:
directive:
app.directive("posts", ['Posts', function(Posts) {
return {
restrict: 'E',
template: '' +
'<div ng-repeat="post in posts"></div>',
scope: {
showLoading: '&',
hideLoading: '&',
spot: '#'
},
controller: ['$scope', function ($scope) {
}],
link: function(scope, element, attrs) {
$scope.load = function () {
Posts.loadPostsBySpot(scope.spot)
};
}
};
}]);
Controller
app.controller('spotPageController', ['$scope', 'Spots', function ($scope, $Spots) {
doit = function () {
Spots.getSpot($)
.success(function (data) {
$scope.spotId = data.data;
console.log($scope.spot);
}).error(function (data) {
console.log('error');
});
};
}]);
html inside
<posts spot="{{spotId}}" showLoading="showLoading()" hideLoading="hideLoading()"></posts>
but when the directive is loaded the "spot" is not yet set,
so how do I make the directive load only after the spot is set.
Use ng-if.
<posts ng-if="spotId" spot="{{spotId}}" showLoading="showLoading()" hideLoading="hideLoading()"></posts>
This element will be rendered only after the spotId is initialized. Therefore, your directive will not be called before that.
If you want to encapsulate this behavior in directive, you should watch for changes of the scopeId. See the fiddle.
Hi I have a variable on my scope named loadingdata. It will have the values true or false to determine if data is loading or not. I would like to put an attribute on an element to disable it if data is loading. Here is the code I already have but it is not working:
module.directive('disableWhenLoadingData', function () {
return {
restrict: 'A',
scope: {},
link: function ($scope, element, attrs) {
$scope.$watch('loadingData', function(newValue, oldValue) {
element.attr('disabled', newValue);
});
}
};
});
any ideas
You can use Angular's own ngDisabled directive instead of writing your own.
Service:
module.factory('GetDataService', function ($http) {
return {
getCustomers: function() {
return $http({ url: '/someurl', method: 'GET'});
}
}
});
Directive:
module.directive('disableWhenLoadingData', function (GetDataService) {
return {
restrict: 'A',
scope: {},
link: function ($scope, element, attrs) {
$scope.loadingData = true;
GetDataService.getCustomers().success(function (data) {
$scope.loadingData = false;
});
}
};
});
Generally I set $scope.loading in my controller, and my button or whatever i set ng-disabled.
In my controller:
$scope.loadData = function () {
$scope.loading = true;
$http
.get('url')
.success(function (ret) {
$scope.loading = false;
});
}
In my view:
<button ng-disabled="loading" ng-click="loadData()">{{loading? 'loading Data' : 'Submit'}}</button>
// Code goes here
var mymodule = angular.module('myapp', []);
mymodule.controller('mycontroller', function ($scope) {
});
mymodule.directive('pvTempUrl',
function ($http, $compile, $log, $templateCache) {
$log.info("Directive Called");
return {
restrict: 'A',
replace: true,
compile: function (telement, tattr, transclude) {
var templateloader = $http.get(tattr.pvTempUrl, { cache: $templateCache }).
success(function (data) {
$log.info("Success-" + data);
telement.html(data);
}).
error(function (data, status) {
$log.warn("Error occured - " + data + " status-" + status);
});
return function (scope, element, attr) {
templateloader.then(function () {
var compiledHtm = ($compile(telement.html())(scope)).html();
$log.info("compiled html-" + compiledHtm);
element.html(compiledHtm);
});
};
}
};
});
I have a partial page trying to compile the page is working just showing the template as such.
Plunkr is avaliable here
http://plnkr.co/edit/U85rmXhuQGKx5pkzUu99?p=preview
Issue found i was binding the html not the compiled object resolved the issue like below
// Code goes here
var mymodule = angular.module('myapp', []);
mymodule.controller('mycontroller', function ($scope) {
});
mymodule.directive('pvTempUrl',
function ($http, $compile, $log, $templateCache) {
$log.info("Directive Called");
return {
restrict: 'A',
replace: true,
compile: function (telement, tattr, transclude) {
var templateloader = $http.get(tattr.pvTempUrl, { cache: $templateCache }).
success(function (data) {
$log.info("Success-" + data);
telement.html(data);
}).
error(function (data, status) {
$log.warn("Error occured - " + data + " status-" + status);
});
return function (scope, element, attr) {
templateloader.then(function () {
var compiledHtm = ($compile(telement.html())(scope));
$log.info("compiled html-" + compiledHtm);
//element.html(compiledHtm);
element.replaceWith(compiledHtm);
$log.info(element.html());
});
};
}
};
});
I haven't seen anyone try to load a template this way before. The proper Angular ways of loading a template are the following:
Using ng-view to load a predefined template file.
Building your own custom directive.
I feel like you are attempting to do the second method. The following code sample is an example of how to do that.
angular.module("myapp")
.directive('buttonsRadio', function() {
return {
restrict: 'E',
scope: false,
controller: function($scope){
//Any logic required for directive to work.
},
templateUrl: 'template.html'
};
})
In your template.html file you would have your template you wish to load.
For much more detail and examples on how to build your own custom directive elements, see the section Writing Directives (long version) in the Angular docs.
UPDATE: Edited to show example of templateUrl.