I've tried to do this in many ways, ui-sref is not working for me ok because data make it undefined by the time it is created.
I'm quite new even programming but fighting a lot with angular these days.
The point is that is this possible to really create a fully custom $state.go?
When I say fully custom is, how can i construct even the key of the parameter?
In:
$state.go(stateName, {key:value}
Thanks
angular.module('app').directive('directive', ['$state', function ($state) {
function link(scope, elements, attibutes) {
//variable data coming example
data = {
name: 'name',
params: {
key: 'id',
value: 'sidvalue'
}
}
scope.back = function (data) {
$state.go(data.name, '{' + data.params.key + ':"' + data.params.value + '"}');
}
}
return {
restrict: 'E',
link: link,
templateUrl: 'path.html'
};
}]);
EDIT: *********
This is the historic factory gathering info from each state with push and getting it from with my logic when is convenient with get:
angular.module('app').factory('Historic', ['$q', '$state', function ($q, $state) {
var historic = [];
return {
historic: {
push: function (key, value) {
var str, init = 'general.home';
str = {
name: $state.current.name,
params: {
key: key,
value: value
}
};
if ($state.current.name === init) {
historic = [{
name: $state.current.name,
}];
} else if (historic.length <= 0) {
historic.push({name: init});
} else if (historic[historic.length - 1].name !== str.name && historic[historic.length - 1].params !== str.params) {
historic.push(str);
}
},
get: function () {
var h = historic[historic.length - 2];
if (historic.length === 1) {
h = historic[0];
}
return $q(function (resolve, reject) {
resolve(h);
});
},
pop: function () {
historic.pop();
},
status: function () {
return historic.length;
}
}
};
}]);
For getting it I'm using a directive with a bit more code attached.
Publishing only the related to historic part.
angular.module('app').directive('directiveName', ['$state', 'fHistoric', function ($state, fHistoric) {
function link(scope, elements, attibutes) {
/*
historic setup
*/
if (fHistoric.historic.status > 3) {
scope.home = true;
}
function keycomp(data) {
if (data.params) {
key = {id: data.params.value};
} else {
key = {};
}
}
scope.back = function () {
fHistoric.historic.get()
.then(function (data) {
keycomp(data);
if (key) {
$state.go(data.name, key);
} else {
$state.go(data.name);
}
});
fHistoric.historic.pop();
};
}
return {
restrict: 'E',
link: link,
scope: {
header: '#',
state: '#'
},
templateUrl: 'path.html'
};
}]);
I really don't like the solution proposed, it is working but the problem with the key values made me to wrap some spaguetti code I really don't like to solve the id: coming from the key value.
Open to new ideas. ;)
Related
I want to dynamically compile component for inserting this to specific DOM element (DOM also dynamically created by 3rd party library).
So, I use $compile, $scope.
https://jsbin.com/gutekat/edit?html,js,console,output
// ListController $postLink life cycle hook
function $postLink() {
...
$timeout(function () {
ctrl.items.splice(0, 1);
$log.debug('First item of array is removed');
$log.debug(ctrl.items);
}, 2000);
}
but below $onChanges life cycle hook in ListItemController isn't executed.
// ListItemController $onChanges life cycle hook
function $onChanges(changes) {
if (!changes.item.isFirstChange()) {
$log.debug(changes); // Not executed
}
}
I guess that angular.merge to pass item before ListItemController controller instance initialization is a major cause.
var itemScope = $scope.$new(true, $scope);
itemScope = angular.merge(itemScope, {
$ctrl: {
item: item
}
});
I modified you code a bit to demonstrate what is going on w/ the one way binding.
angular.module('app', [
'list.component',
'list-item.component'
]);
/**
* list.component
*/
angular
.module('list.component', [])
.component('list', {
controller: ListController,
template: '<div id="list"></div>'
});
ListController.$inject = ['$compile', '$document', '$log', '$scope', '$timeout'];
function ListController($compile, $document, $log, $scope, $timeout) {
var ctrl = this;
ctrl.$onInit = $onInit;
ctrl.$postLink = $postLink;
function $onInit() {
ctrl.items = [
{
id: 0,
value: 'a'
},
{
id: 1,
value: 'b'
},
{
id: 2,
value: 'c'
}
];
}
function $postLink() {
var index = 0;
// Not entirely sure what you need to do this. This can easily be done in the template.
/** ie:
* template: '<div id="list" ng-repeat="item in $ctrl.items"><list-item item="item"></list-item></div>'
**/
var iElements = ctrl.items.map(function (item) {
var template = '<list-item item="$ctrl.items[' + (index) + ']"></list-item>';
index++;
// you don't want to create an isolate scope here for the 1 way binding of the item.
return $compile(template)($scope.$new(false));
});
var listDOM = $document[0].getElementById('list');
var jqListDOM = angular.element(listDOM);
iElements.forEach(function (iElement) {
jqListDOM.append(iElement);
});
$timeout(function () {
// this will trigger $onChanges since this is a reference change
ctrl.items[0] = { id: 3, value: 'ss' };
// this however, will not trigger the $onChanges, if you need to use deep comparison, consider to use $watch
ctrl.items[1].value = 's';
ctrl.items[2].value = 's';
}, 2000);
}
}
/**
* list-item.component
*/
angular
.module('list-item.component', [])
.component('listItem', {
bindings: {
item: '<'
},
controller: ListItemController,
template: '<div class="listItem">{{ $ctrl.item.value }}</div>'
});
ListItemController.$inject = ['$log'];
function ListItemController($log) {
var ctrl = this;
ctrl.$onChanges = $onChanges;
function $onChanges(changes) {
if (!changes.item.isFirstChange()) {
$log.debug(changes); // Not executed
}
}
}
I would like to know how can we get the selected checkbox values from tree in controller from the below example? On click of a button i want to display all the checkbox names in an array. Here is my plnkr- https://plnkr.co/edit/OSpLLl9YrlzqhM7xsYEv?p=preview
//code goes here,
//Controller
Controller to display the tree.
(function (ng) {
var app = ng.module('tree', ['tree.service', 'tree.directives']);
app.controller("TreeController", ["TreeService", function (TreeService) {
var tc = this;
buildTree();
function buildTree() {
TreeService.getTree().then(function (result) {
tc.tree = result.data;
}, function (result) {
alert("Tree no available, Error: " + result);
});
}
}]);
})(angular);
//Tree Directive
Directive used for creating tree node.
(function (ng) {
var app = ng.module('tree.directives', []);
app.directive('nodeTree', function () {
return {
template: '<node ng-repeat="node in tree"></node>',
replace: true,
restrict: 'E',
scope: {
tree: '=children'
}
};
});
app.directive('node', function ($compile) {
return {
restrict: 'E',
replace: true,
templateUrl: 'node.html', // HTML for a single node.
link: function (scope, element) {
/*
* Here we are checking that if current node has children then compiling/rendering children.
* */
if (scope.node && scope.node.children && scope.node.children.length > 0) {
scope.node.childrenVisibility = true;
var childNode = $compile('<ul class="tree" ng-if="!node.childrenVisibility"><node-tree children="node.children"></node-tree></ul>')(scope);
element.append(childNode);
} else {
scope.node.childrenVisibility = false;
}
},
controller: ["$scope", function ($scope) {
// This function is for just toggle the visibility of children
$scope.toggleVisibility = function (node) {
if (node.children) {
node.childrenVisibility = !node.childrenVisibility;
}
};
// Here We are marking check/un-check all the nodes.
$scope.checkNode = function (node) {
node.checked = !node.checked;
function checkChildren(c) {
angular.forEach(c.children, function (c) {
c.checked = node.checked;
checkChildren(c);
});
}
checkChildren(node);
};
}]
};
});
})(angular);
Hello: Look at this plunker link. It works here
https://plnkr.co/edit/vaoCzUJZBf31wtLNJ5f5?p=preview
(function (ng) {
var app = ng.module('tree', ['tree.service', 'tree.directives']);
app.controller("TreeController", ["TreeService", "$scope", function (TreeService, $scope) {
var tc = this;
buildTree();
function buildTree() {
TreeService.getTree().then(function (result) {
tc.tree = result.data;
}, function (result) {
alert("Tree no available, Error: " + result);
});
}
$scope.selectedItems = [];
$scope.getSelected = function(){
$scope.selectedItems = [];
function checkChildren(c) {
angular.forEach(c.children, function (c) {
if (c.checked){
$scope.selectedItems.push({"selected":c.name});
}
checkChildren(c);
});
}
angular.forEach(tc.tree, function(value, key) {
if (value.checked){
$scope.selectedItems.push({"selected":value.name});
}
checkChildren(value);
});
};
}]);})(angular);
I have a page where I need to hit 2 restful web service calls. 1st rest call is successful and I am getting back the data. After hitting 2nd service, still the data of 1st call is persisted in the variable. So using call back method is the solution for this?If so, how to write callback method in angularjs way?
Here is my code.
app.directive('collection', function() {
return {
restrict: "E",
replace: true,
scope: {
collection: '=',
articleData: '=',
articleContent: '='
},
template: "<ul><member ng-repeat='member in collection' member='member' article-data='articleData' article-content='articleContent'></member></ul>"
}
});
app.directive('member', function($compile,$http,getTocService) {
return {
restrict: "A",
replace: true,
scope: {
member: '=',
articleData: '=',
articleContent: '='
},
template: "<div><li><a href='#' ng-click='getContent(member.itemId)'>{{member.title}}</a></li></div>",
link: function(scope, element, attrs) {
scope.getContent = function(itemId) {
var art = getTocService.getArtData(itemId);
}
if (angular.isArray(scope.member.tocItem)) {
if (scope.member.hasChildren == "true") {
for (var i = 0; i < scope.member.tocItem.length; i++) {
if (scope.member.tocItem.title) {
scope.member.tocItem.title.hide = true;
}
}
}
element.append("<collection collection='member.tocItem'></collection>");
$compile(element.contents())(scope)
}
}
}
});
app.controller('apdController', function($scope, getTocService,$location) {
var bookId = $location.search().id;
var sampdata = getTocService.getToc(bookId);
$scope.tasks =sampdata;
// $scope.tasks = data;
// var artData = getTocService.getArtData('PH1234');
// $scope.articleContent = artData;
});
app.service(
"getTocService",
function( $http, $q ) {
return({
getToc: getToc,
getArtData: getArtData
});
function getToc(bookIdvar) {
var request = $http({
method: "post",
url: "http://10.132.241.41:8082/apdpoc/services/ApdBookService/getTOC",
params: {
action: "post"
},
data: {
getTOCCriteria:{
bookId: bookIdvar
}
}
});
return( request.then(handleSuccess,handleError));
}
function getArtData(itemId) {
var request = $http({
method: "post",
url: "http://10.132.241.41:8082/apdpoc/services/ApdBookService/getArticle",
params: {
action: "post"
},
data: {
getArticleCriteria:{
articleId: itemId,
locale: "en_US"
}
}
});
alert(data);
return( request.then(handleSuccess,handleError));
}
function handleSuccess(response){
return (response.data);
}
function handleError( response ) {
if (
! angular.isObject(response.data) ||
! response.data.message
) {
return($q.reject("An unknown error occurred."));
}
return($q.reject(response.data.message));
}
}
);
Here, "data" is the variable I am using in both the calls to hold the response data. And I am calling 2nd service "getArtData" from
var art = getTocService.getArtData(itemId);
You should strongly consider using promises. Promises allow chaining and are a lot better than callback hell. The keyword here is using then.
This SO post explains it better: Processing $http response in service
Hope this is helpful to you.
Your getTocService returns promises and you need to chain the two promises.
var bookId = $location.search().id;
var sampdataPromise = getTocService.getToc(bookId);
sampdataPromise.then( function(data) {
$scope.tasks = data;
//return next promise for chaining
return getTocService.getArtData(data.itemId);
}).then (function (artData) {
$scope.articleContent = artData;
}).catch (function (error) {
//log error
});
I am trying to create a tag layout filled with categories, but I am not getting my Authentication because I am trying to resolve that service in my Router.
this is my Router code
(function () {
'use strict';
angular
.module('learningApp')
.config(sslRouter);
// Minification safe dependency Injection
sslRouter.$inject = ['$stateProvider'];
function sslRouter ($stateProvider) {
// SSL Route Definition
$stateProvider.state('ssl', {
parent: 'policy',
url: '/ssl',
data: {
roles: ['USER']
},
views: {
'policyConfig': {
templateUrl: 'components/configuration/service/policy/ssl/ssl.tpl.html',
controller: 'SSL'
}
},
resolve: {
'sslServiceData': function(sslService) {
return sslService.promise;
}
}
});
}
}());
This is my Service
(function() {
'use strict';
angular
.module('learningApp')
.factory('sslService', sslResource);
sslResource.$inject = ['Principal', '$resource', 'BASE_URL', 'exDomainService'];
function sslResource (Principal, $resource, BASE_URL, exDomainService) {
debugger;
var res = $resource(BASE_URL + '/api/companies/' + Principal.company() + '/sconfig/ssl/sslConfiguration', {}, {
query: {
method: 'GET',
isArray: false
},
update: {
method: 'PUT'
}
});
var data = {};
var servicePromise = _initService();
servicePromise.$promise.then(function (d) {
data = d;
if (!data.excludedCategories) {
data.excludedCategories = [];
}
if (!data.excludedDomains) {
data.excludedDomains = [];
}
exDomainService.tableData = getExcludedDomains();
});
function _initService () {
return res.query();
}
return {
promise: servicePromise,
rest: res
}
}
}());
This is my controller
(function() {
'use strict';
angular
.module('learningApp')
.controller('SSL', SSLController);
SSLController.$inject = ['$scope', 'sslService', 'preDefinedCategoryService', '$timeout', 'exDialog', 'exDomainService'];
function SSLController ($scope, sslService, preDefinedCategoryService, $timeout, exDialog, exDomainService) {
var vm = $scope;
/**
* #desc Flags for different type checks
* Booleans and Categories
*/
vm.flags = {
// By default true
enableInspectSSLTraffic: sslService.getSSlInspectionFlag(),
allowUntrustedCertificates: sslService.getUntrustedCertificatesFlag(),
allowHostnameMismatch: sslService.getHostnameMismatchFlag(),
selectedCategory: undefined,
initializing: true
};
vm.excludedCategories = sslService.getExcludedCategories();
vm.predefinedCategories = preDefinedCategoryService.rest.query();
vm.predefinedCategories.$promise.then(function() {
vm.categories = _processedCategories(vm.predefinedCategories, vm.excludedCategories);
});
}
}());
So basically problem is, I am getting Principal.Identity as undefined, but if I remove resolution from Router, I got identity but then I lose my data coming from service. I want my service to be loaded completely before its Controller, and I want my principal service to be loaded before service.
for Reference, This is my Principal Class
'use strict';
angular.module('learningApp')
.service('Principal',['$q', 'Account', 'localStorageService', function Principal($q, Account, localStorageService) {
var _identity,
_authenticated = false;
return {
isIdentityResolved: function () {
return angular.isDefined(_identity);
},
isAuthenticated: function () {
return _authenticated;
},
isInRole: function (role) {
if (!_authenticated || !_identity || !_identity.roles) {
return false;
}
return _identity.roles.indexOf(role) !== -1;
},
isInAnyRole: function (roles) {
if (!_authenticated || !_identity.roles) {
return false;
}
for (var i = 0; i < roles.length; i++) {
if (this.isInRole(roles[i])) {
return true;
}
}
return false;
},
company: function () {
debugger;
if (_identity) return _identity.companyId;
},
authenticate: function (identity) {
_identity = identity;
_authenticated = identity !== null;
},
identity: function (force) {
var deferred = $q.defer();
if (force === true) {
_identity = undefined;
}
// check and see if we have retrieved the identity data from the server.
// if we have, reuse it by immediately resolving
if (angular.isDefined(_identity)) {
deferred.resolve(_identity);
return deferred.promise;
}
// rather than retrieving from server, use cookie or whatever method
var cookieFound = UTIL.cookie("token");
if (cookieFound) {
var response = JSON.parse(JSON.parse(cookieFound));
var expiredAt = new Date();
expiredAt.setSeconds(expiredAt.getSeconds() + response.expires_in);
response.expires_at = expiredAt.getTime();
localStorageService.set('token', response);
}
// retrieve the identity data from the server, update the identity object, and then resolve.
Account.get().$promise
.then(function (account) {
account.data.roles = ["ADMIN", 'USER'];
account.data.langKey = "en";
_identity = account.data;
_authenticated = true;
deferred.resolve(_identity);
})
.catch(function() {
_identity = null;
_authenticated = false;
deferred.resolve(_identity);
});
return deferred.promise;
}
};
}]);
I have created a directive below:
html:
<div image-upload></div>
directive:
angular.module('app.directives.imageTools', [
"angularFileUpload"
])
.directive('imageUpload', function () {
// Directive used to display a badge.
return {
restrict: 'A',
replace: true,
templateUrl: "/static/html/partials/directives/imageToolsUpload.html",
controller: function ($scope) {
var resetScope = function () {
$scope.imageUpload = {};
$scope.imageUpload.error = false;
$scope.imageUpload['image_file'] = undefined;
$scope.$parent.imageUpload = $scope.imageUpload
};
$scope.onImageSelect = function ($files) {
resetScope();
$scope.imageUpload.image_file = $files[0];
var safe_file_types = ['image/jpeg', 'image/jpg']
if (safe_file_types.indexOf($scope.imageUpload.image_file.type) >= 0) {
$scope.$parent.imageUpload = $scope.imageUpload
}
else {
$scope.imageUpload.error = true
}
};
// Init function.
$scope.init = function () {
resetScope();
};
$scope.init();
}
}
});
This directive works fine and in my controller I access $scope.imageUpload as I required.
Next, I tried to pass into the directive a current image but when I do this $scope.imageUpload is undefined and things get weird...
html:
<div image-upload current="project.thumbnail_small"></div>
This is the updated code that gives the error, note the new current.
angular.module('app.directives.imageTools', [
"angularFileUpload"
])
.directive('imageUpload', function () {
// Directive used to display a badge.
return {
restrict: 'A',
replace: true,
scope: {
current: '='
},
templateUrl: "/static/html/partials/directives/imageToolsUpload.html",
controller: function ($scope) {
var resetScope = function () {
$scope.imageUpload = {};
$scope.imageUpload.error = false;
$scope.imageUpload['image_file'] = undefined;
$scope.$parent.imageUpload = $scope.imageUpload
if ($scope.current != undefined){
$scope.hasCurrentImage = true;
}
else {
$scope.hasCurrentImage = true;
}
};
$scope.onImageSelect = function ($files) {
resetScope();
$scope.imageUpload.image_file = $files[0];
var safe_file_types = ['image/jpeg', 'image/jpg']
if (safe_file_types.indexOf($scope.imageUpload.image_file.type) >= 0) {
$scope.$parent.imageUpload = $scope.imageUpload
}
else {
$scope.imageUpload.error = true
}
};
// Init function.
$scope.init = function () {
resetScope();
};
$scope.init();
}
}
});
What is going on here?
scope: {
current: '='
},
Everything works again but I don't get access to the current value.
Maybe I'm not using scope: { correctly.
in your updated code you use an isolated scope by defining scope: {current: '=' } so the controller in the directive will only see the isolated scope and not the original scope.
you can read more about this here: http://www.ng-newsletter.com/posts/directives.html in the scope section