Can't update view from $timeout - javascript

I'm loading a page with 3 collapsible panels, all containing a grid.
I can successfully load the panel as expanded (also tested with collapsed), using this code:
var component = {
bindings: {
configurationMigrationLogs: '<'
},
template: require("./reMigrationConfiguration.template.html"),
controller: ControllerFn,
controllerAs: 'vm'
};
ControllerFn.$inject = ['$timeout'];
function ControllerFn($timeout) {
const vm = this;
vm.isCardOpen = true; //Does work.
$timeout(function (vm) {
vm.isCardOpen = false; //Doesn't work.
console.log(vm);
}, 3000, true, vm);
}
export default function (app) {
app.component('reMigrationConfiguration', component);
}
However, when I try to collapse the panel in the $timeout function, it doesn't work.
I can see the vm.isCardOpen property is updated to false, in the console window.
But the panel remains expanded.
Here's the HTML:
<re-card is-collapsed="true" is-open="vm.isCardOpen" ng-repeat="configurationMigrationLog in vm.configurationMigrationLogs">
<!--grid code here-->
</re-card>
The re-card component is set up in this .js:
(function() {
'use strict';
angular.module('app.components')
.directive('reCard', directiveFn);
directiveFn.$inject = ['$timeout'];
function directiveFn($timeout) {
var directive = {
restrict:'EA',
scope:true,
priority:10,
controller:controllerFn,
transclude:true,
controllerAs:'reCard',
template: '<div>' +
'<div re-blocked="isBlocked" re-loading="isBusy"> ' +
'<div class="grid simple fadeIn animated" ' +
'ng-class="{collapsible:isCollapsible, \'is-open\':!isCollapsed }" ' +
're-transclude></div>' +
'</div></div>',
link:{
pre:preLinkFn,
post:postLinkFn
}
};
return directive;
function preLinkFn(scope, ele, attrs) {
if (attrs.isCollapsed) {
scope.isCollapsed = scope.$eval(attrs.isCollapsed);
scope.isCollapsible = attrs.isCollapsed;
scope.isOpen = scope.$eval(attrs.isOpen);
}
}
function postLinkFn(scope, ele, attrs, ctrl) {
var blockWatcher, obsv;
scope.isBusy = false;
if (attrs.notifyOfToggle) {
ctrl.registerNotifyOfToggle(attrs.notifyOfToggle);
}
if (attrs.isBlocked) {
blockWatcher = scope.$parent.$watch(attrs.isBlocked, function(val) {
scope.isBlocked = val;
});
}
if (attrs.hasOwnProperty('isBusy')) {
obsv = attrs.$observe('isBusy', function(val) {
if (val && scope.$eval(val)) {
scope.isBusy = true;
}
else {
scope.isBusy = false;
}
});
}
scope.$on('destroy', function() {
blockWatcher();
});
attrs.$observe('isOpen', function(val) {
if (typeof(val) !== 'undefined') {
ctrl.toggleCollapsed(!scope.$eval(val));
}
});
}
}
controllerFn.$inject = ['$scope'];
function controllerFn($scope) {
var notifyOfToggle = null;
this.getScope = function() {
return $scope;
};
this.toggleCollapsed = function(val) {
if (typeof($scope.isCollapsed) !== 'undefined') {
if (angular.isDefined(val)) {
$scope.isCollapsed = val;
} else {
$scope.isCollapsed = !$scope.isCollapsed;
}
if (notifyOfToggle) {
$scope.$eval(notifyOfToggle);
}
}
};
this.registerNotifyOfToggle = function(notifyOfToggleFromAttrs) {
notifyOfToggle = notifyOfToggleFromAttrs;
};
}
})();

Binding your is-open attribute should fix it:
<re-card is-collapsed="true" is-open="{{vm.isCardOpen}}" ng-repeat="configurationMigrationLog in vm.configurationMigrationLogs">
<!--grid code here-->
</re-card>

Related

get selected checkbox values from tree in angularjs

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);

Angular custom directive not showing label for select input

For some reason the label for select input field is not showing. I have made a custom directive for it, which looks like this:
angular.module('quiz.directives')
.directive('fancySelect', function($rootScope, $timeout) {
return {
restrict: 'E',
templateUrl: 'templates/directives/fancySelect.html',
scope: {
title: '#',
model: '=',
options: '=',
multiple: '=',
enable: '=',
onChange: '&',
class: '#'
},
link: function(scope) {
scope.showOptions = false;
scope.displayValues = [];
scope.$watch('enable', function(enable) {
if (!enable && scope.showOptions) {
scope.toggleShowOptions(false);
}
});
scope.toggleShowOptions = function(show) {
if (!scope.enable) {
return;
}
if (show === undefined) {
show = !scope.showOptions;
}
if (show) {
$rootScope.$broadcast('fancySelect:hideAll');
}
$timeout(function() {
scope.showOptions = show;
});
};
scope.toggleValue = function(value) {
if (!value) {
return;
}
if (!scope.multiple) {
scope.model = value;
return;
}
var index = scope.model.indexOf(value);
if (index >= 0) {
scope.model.splice(index, 1);
}
else {
scope.model.push(value);
}
if (scope.onChange) {
scope.onChange();
}
};
scope.getDisplayValues = function() {
if (!scope.options || !scope.model) {
return [];
}
if (!scope.multiple && scope.model) {
return scope.options.filter(function(opt) {
return opt.id == scope.model;
});
}
return scope.options.filter(function(opt) {
return scope.model.indexOf(opt.id) >= 0;
});
};
$rootScope.$on('fancySelect:hideAll', function() {
scope.showOptions = false;
});
}
};
});
And in my template I am inserting the directive like this:
<fancy-select
title="Klassetrinn"
model="selected.year"
ng-model="user.year"
options="years"
enable="true"
on-change="onChangeYears()"
active="yearsActive"
name="playerYear"
form-name="registerForm"
>
</fancy-select>
And then in my profile I am getting the value for selected year like this:
$http.get(AppSettings.apiUrl + '/years')
.then(function(result) {
$scope.years = result.data;
});
$scope.selected = {
year: []
};
user.player.year = $scope.selected.year;
But for some reason the label "Klassetrinn" is not shown in the template, not sure why is that?

How catch changes in scope variable made in directive?

I have some directive for html:
<dropdown placeholder='' list='sizeWeightPriceArr' selected='selectedProductSize' property='size' value='size' style='width:60px;'></dropdown>
selectedProductSize => scope variable. Basic idea => I selected some value in dropdown and this variable in selected attribute save all changes.
JS:
.directive('dropdown', ['$rootScope', function($rootScope) {
return {
restrict: "E",
templateUrl: "templates/dropdown.html",
scope: {
placeholder: "#",
list: "=",
selected: "=",
property: "#",
value: "#"
},
link: function(scope, elem, attr) {
scope.listVisible = false;
scope.isPlaceholder = true;
scope.select = function(item) {
scope.isPlaceholder = false;
scope.selected = item[scope.value];
scope.listVisible = false;
};
scope.isSelected = function(item) {
return item[scope.value] === scope.selected;
};
scope.show = function() {
scope.listVisible = true;
};
$rootScope.$on("documentClicked", function(inner, target) {
if(!$(target[0]).is(".dropdown-display.clicked") && !$(target[0]).parents(".dropdown-display.clicked").length > 0) {
scope.$apply(function() {
scope.listVisible = false;
});
}
});
scope.$watch('selected', function(value) {
if(scope.list != undefined) {
angular.forEach(scope.list, function(objItem) {
if(objItem[scope.value] == scope.selected) {
scope.isPlaceholder = objItem[scope.property] === undefined;
scope.display = objItem[scope.property];
}
});
}
});
scope.$watch('list', function(value) {
angular.forEach(scope.list, function(objItem) {
if(objItem[scope.value] == scope.selected) {
scope.isPlaceholder = objItem[scope.property] === undefined;
scope.display = objItem[scope.property];
}
});
});
}
}
}])
dropdown.html don't irrelevant. When I make selection scope.select function run inside directive and in scope.selected = item[scope.value]; set selected value. It is working. Then in controller I try to write $scope.$watch to catch changes and run function but it won't work:
$scope.selectedProductSize = '';
$scope.$watch('selectedProductSize', function(value) {
...
});
You don't need to user $watch you can pass in the variable to the directive with two way data binding
in your controller
$scope.my_var = ''
directive html
myvar=my_var
directive
scope: {
myvar: '='
}
$scope.my_var will be bound to the directive myvar so anytime scope.myvar changes in your directive, $scope.my_var will also be updated in your controller

$watch is not called in angularjs

Hi I am newbie to angular I am trying to update using ng-click directive and $watch function. On first click it is getting updated but second time it doesn't get updated. Bare my english and little knowledge Here is my code.
angular.module('charts', [])
.factory('socket', ['$rootScope', function ($rootScope) {
var safeApply = function(scope, fn) {
if (scope.$$phase) {
fn(); // digest already in progress, just run the function
} else {
scope.$apply(fn); // no digest in progress, run with $apply
}
};
var socket = io.connect('http://localhost:5000/');
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
safeApply($rootScope, function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
safeApply($rootScope, function () {
if (callback) {
callback.apply(socket, args);
}
});
})
},
disconnect: function () {
socket.disconnect();
},
socket: socket
};
}])
.controller('mainCtrl',['$scope','socket', function AppCtrl ($scope, socket) {
$scope.options = {width: 500, height: 300, 'bar': 'aaa'};
$scope.data = {"angular":12,"js":15};
$scope.hovered = function(d){
$scope.barValue = d.name;
//$scope.$apply();
};
$scope.barValue = 'None';
}])
.directive('barChart', function(){
var chart = d3.custom.barChart();
return {
restrict: 'E',
replace: true,
template: '<div class="chart"></div>',
scope:{
height: '=height',
data: '=data',
hovered: '&hovered'
},
link: function(scope, element, attrs) {
var chartEl = d3.select(element[0]);
chart.on('customHover', function(d, i){
scope.hovered({args:d});
});
scope.$watch('data', function (newVal, oldVal) {
console.log(newVal);
chartEl.datum(newVal).call(chart);
});
scope.$watch('height', function(d, i){
chartEl.call(chart.height(scope.height));
})
}
}
})
.directive('chartForm', function(){
return {
restrict: 'E',
replace: true,
controller: function AppCtrl ($scope, socket) {
$scope.start = function(d, i) {
$scope.btnIsDisabled = true;
socket.on("connected",function(r){ console.log('breakpoint 1');/*console.log(r);*/ });
socket.on("new tweet", function(tweet) {
var hashtags = tweet.entities.hashtags;
if(hashtags.length) {
_.each(hashtags, function(hashtag) {
hashtag = hashtag.text.toLowerCase();
// if(hashtag == 'food' || hashtag == 'pizza' || hashtag == 'samosa') {
// console.log(hashtag);
if(_hashtags[hashtag]) {
_hashtags[hashtag]++;
}
else {
_hashtags[hashtag] = 1;
}
//}
});
}
num_tweets++;
});
};
$scope.update = function(d, i) {
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.safeApply( function() {
console.log(JSON.stringify(_hashtags));
$scope.data = _hashtags;
});
};
},
template: '<div class="form">' +
'Height: {{options.height}}<br />' +
'<input type="range" ng-model="options.height" min="100" max="800"/>' +
'<br /><button ng-click="start()" ng-disabled="btnIsDisabled">Start</button>'+
'<button ng-click="update()" ng-disabled="false">Update Data</button>' +
'<br />Hovered bar data: {{barValue}}</div>'
}
});

Strange behavior passing scope to directive

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

Categories

Resources