We're moving from using angular modal to uibmodal for creating our modals. Previously we accessed our form elements for the template passed in using link
ModalService.showModal({
templateUrl: templateUrl,
controller: controller,
controllerAs: controllerAs,
inputs: {apiMethod: apiMethod, callback: callback, params : params},
link: function(scope, element, attr) {
scope.dismiss = function() {
element.modal('hide');
};
}
This isn't an option with uibmodal without creating a new directive. Is there an easy way to access the DOM at this point? We'd like to take the elements in the DOM (text inputs) and pass them to our chosen apimethod.
$uibModal.open({
templateUrl: templateUrl,
controller: controller,
controllerAs: controllerAs,
resolve: {params: function(){return params;},apiMethod: function(){return apiMethod;}}
});
This is what the controller did previously - the issue is that we no longer have access to the element(s):
Controller:
$scope.params = params;
$scope.close = function (result,form) {
if (result == 'Save') {
var uri = apiMethod + "?accountId=" + $routeParams.accountId;
$http.post(uri, formToKeyValueListJSON($element))
.success(function (data, status, headers, config) {
$uibModalInstance.close({status:'Success', data: data}, 500); // close, but give 500ms for bootstrap to animate
})
.error(function (data, status, headers, config) {
$uibModalInstance.close({status:'Fail', data: data},500);
});
}
};
Related
I have one html file.
At that file, I have a button that should open a modal when I click it.
<button ng-click="open(value.Reservation.id)" class="btn btn-default btn-xs" ></button>
and below that button, in the same html file, I have the script.
<script type="text/ng-template" id="myModalContent.html">test</script>
and in the pendingController.js file,
myApp.controller('PendingCtrl', function ($rootScope, $scope, $location, $http, $modal, $log) {
$scope.open = function (id) {
//GET RESERVATION
$http({method: 'GET', url: 'admin/getUpdateReservation/'+ id +'.json'}).
success(function(data, status, headers, config) {
$scope.post = data.data;
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'UpdateReservationCtrl',
resolve: {
data: function () {
$scope.post.status = $scope.status;
$scope.post.locations = $scope.locations;
return $scope.post;
}
}
});
modalInstance.result.then(function (selectedItem) {
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
}).
error(function(data, status, headers, config) {
alert('error');
});
};
})
And I have updateReservationController.js file.
hansApp.controller('UpdateReservationCtrl', function ($rootScope, $scope, $route, $http, $modalInstance, data) {
console.log('6');
})
the console.log('6'); works. But I can't see the modal page...
How can I make my modal works?
So First of all, dont use resolve if you dont wating for a promise...
What docs say to the resolve Key:
Object containing dependencies that will be injected into the
controller's constructor when all the dependencies have resolved. The
controller won't load if the promise is rejected.
It looks like you are using the Modal of AngularStarp (correct me if im wrong).
As they mention in they docs you have to do something like this:
modal = $modal({
controller: function($scope) {},
show: false,
});
and in your success-callback:
modal.$promise.then(modal.show);
I'm trying to initiate a carousel script onto the rendered elements created by my directive. It works if I feed the directive with static json, but if I use http get to get the data from an api it will not initialized properly. While the script does initialize and creates a set of elements for navigation of the carousel it seems the rendered elements are injected after this happens.
If I delay the init with 100ms it'll initialize properly, but it feels like a hacky solution. What's best practice is a situation like this?
Static data – works
angular.module('exhibitions', [])
.directive('exhibitionsCarousel', ['$timeout', function(timer) {
return {
scope: {},
link: function(scope, element, attrs) {
var initFlickity = function () {
var flkty = new Flickity( '.main-gallery', {
cellAlign: 'left',
contain: true
});
};
timer(initFlickity, 0);
},
templateUrl: '/app/themes/pomgallery/exhibitions_carousel.html',
replace: true,
controller: 'exhibitionsCarouselCtrl',
controllerAs: 'ctrl'
};
}])
.controller('exhibitionsCarouselCtrl', function($scope, $http) {
this.exhibitions = [
{title: 'Rachel', date: 'Washington', place: 'One'},
{title: 'Joshua', date: 'Foster', place: 'Two'},
{title: 'Samuel', date: 'Walker', place: 'Three'}
];
});
angular.module('PomGallery', ['exhibitions']);
Fetched data – does not work without delay
angular.module('exhibitions', [])
.directive('exhibitionsCarousel', ['$timeout', function(timer) {
return {
scope: {},
link: function(scope, element, attrs) {
var initFlickity = function () {
var flkty = new Flickity( '.main-gallery', {
cellAlign: 'left',
contain: true
});
};
timer(initFlickity, 0); // If I set it to 100 rather than 0 it'll work.
},
templateUrl: '/app/themes/pomgallery/exhibitions_carousel.html',
replace: true,
controller: 'exhibitionsCarouselCtrl',
controllerAs: 'ctrl'
};
}])
.controller('exhibitionsCarouselCtrl', function($scope, $http) {
var vm = this;
$http({
method: 'GET',
url: '/wp-json/posts',
params: {
'filter[posts_per_page]': 3
},
}).
success( function( data, status, headers, config ) {
vm.exhibitions = data;
}).
error(function(data, status, headers, config) {});
});
angular.module('PomGallery', ['exhibitions']);
You should use a promise. A promise will wait for data before displaying it but it will still run the other functions within the controller, similar to asynchronous functions in c#. Here's the link to the tutorial
https://docs.angularjs.org/api/ng/service/$q
I want to call a function declared inside the link function on my directive after an ajax request on my controller. So I want to communicate the controller with the link function.
This is my controller code:
.controller('productsCtrl', ['$scope', '$location', '$http', function ($scope, $location, $http) {
this.courseSeriesId = $location.search().courseSeriesId;
//FUNCTION: get data from products to show them
this.getCourseSeriesProducts = function(){
$http({
method: 'post',
url: "xxx",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: {
functionName:'xxx',
courseSeriesId: this.courseSeriesId}
})
.success(function(response) {
---CODE
CALL welcome() function in LINK?
---CODE
}.bind(this))
.error(function(data){
alert('ERROR: ' + data);
});
}
And here is my directive code:
.directive('nlProducts', ['$location', function($location) {
return {
restrict: 'E',
templateUrl: function(elem, attr){
var type = '';
switch($location.search().courseSeriesId){
case 'en-efw':
type = 'tableview';break;
}
return 'xxx/nl-products-'+ type+'.php';
},
//control DOM elements
link:
function welcome() {
element.text('hi!');
}
};
}]);
I know that link is called after compilation, but in that moment the ajax request hasn't been finished yet. How can I do it?
Thanks.
You can't directly.
You can either use events with $broadcast in your controller and $on in your directive.
see this answer
or you can use $watch in your directive to look for a change in a variable your controller sets
Here is my state definition:
.state('sub-topic',{
url:"/topics/:topicId",
templateUrl: "templates/sub-topics.html",
controller: "SubTopicsController"
})
Here is my service
myApp.service('subTopicsService',function($http, $stateParams){
this.getSubTopics = function(){
$http.get('topics/' + $stateParams.topicId + '.json').success(function(data, status, header, config) {
return data;
});
}
})
A part of my controller, that has 'subTopicService' injected
$scope.topicList = subTopicsService.getSubTopics();
The problem is, the $stateParams is undefined in the service.
Specifically I get this error message: Cannot access property :topicId of undefined.
How do I use $stateParams in my service?
This scenario should work. There is a working plunker. Changes I made:
I just restructred the service definition:
myApp.service('subTopicsService', function($http, $stateParams) {
var getSubTopics = function() {
$http.get('topics/' + $stateParams.topicId + '.json ')
.success(function(data, status, header, config) {
return data;
});
};
// to prove, that this service can work with $stateParams
var getStateParams = function() {
return $stateParams;
};
return {
getSubTopics: getSubTopics,
getStateParams: getStateParams,
};
});
Here we get the service injected into controller:
myApp.controller('SubTopicsController', function($scope, $state, subTopicsService) {
$scope.stateParams = subTopicsService.getStateParams();
});
And here is our view, consuming that all:
$stateProvider
.state('sub-topic', {
url: "/topics/:topicId",
//templateUrl: "templates/sub-topics.html",
template: '<div><pre>{{stateParams}}</pre></div>',
controller: "SubTopicsController",
});
See the working plunker for more detauls
// 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.