Update scope variable in directive not updating the visual - angularjs

I have a simple slideshow. I introduced a new scope variable called 'isLoading'. The idea is to disable the Next button until the image is fully loaded. However the Next button remains disabled. The UI is not detecting that the scope variable has changed.
<html>
<link rel="stylesheet" href="bootstrap.min.css">
<script src='angular.min.js'></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.slides = [
{filename : 'Slide5.jpg', type : 'image'},
{filename : 'Slide1.PNG', type : 'image'},
];
$scope.page = 0;
setCurrentSlide();
$scope.previous = function() {
$scope.page--;
setCurrentSlide();
};
$scope.next = function() {
$scope.page++;
setCurrentSlide();
};
$scope.completed = function() {
alert('done');
};
function setCurrentSlide() {
$scope.isLoading = true;
$scope.currentSlide = $scope.slides[$scope.page];
}
});
app.directive('imgloader', [function () {
return {
restrict: 'A',
link: function (scope, ele) {
ele.bind('load', function () {
scope.isLoading = false;
});
}
};
}]);
</script>
<body ng-app="myApp" ng-controller="myCtrl">
<div class="slidecontainer">
<img imgloader ng-if="currentSlide.type == 'image'" src='{{currentSlide.filename}}'/>
<video ng-if="currentSlide.type == 'video'" controls>
<source src="{{currentSlide.filename}}"/>
</video>
</div>
</div>
<div class="controlscontainer">
<span class="slidenumbers">Slide {{page+1}} / {{slides.length}}</span>
<button ng-click="previous()" ng-disabled="page <= 0" class="btn btn-lg btn-primary">Previous</button>
<button ng-click="next()" ng-disabled="isLoading || page >= slides.length-1" class="btn btn-lg btn-primary">Next</button>
<button ng-click="completed()" ng-disabled="page != slides.length-1" class="btn btn-lg btn-success">Complete</button>
</div>
</body>
</html>

You are mixing the scope of your directive with the $scope of your controller:
notice that this 2 reffer to different contexts scope.isLoading !== $scope.isLoading
instead you colud try:
<img ng-load="isLoading = false" ng-if="currentSlide.type == 'image'" src='{{currentSlide.filename}}'/>
Where isLoading referes to the property on the $scope of your controller

Related

Image is not changing even i changed image

In angularjs if i change or remove image it does not make any changes. After refreshing the page it show the changed image.I am using following line to remove image
jQuery
$('#profile_image').val('')
This Sample is basic if you want to know more about AngularJs click on link
var app = angular.module("app", []);
app.controller("ctrl", [
"$scope",
function($scope) {
$scope.imgShow = true;
$scope.imgSrc = "https://www.gravatar.com/avatar/75025ad9a8cfdaa5772545e6e8f41133?s=32&d=identicon&r=PG&f=1";
$scope.display = function() {
$scope.imgShow = true;
$scope.imgSrc = "https://www.gravatar.com/avatar/75025ad9a8cfdaa5772545e6e8f41133?s=32&d=identicon&r=PG&f=1";
}
$scope.change = function() {
$scope.imgSrc = "https://www.gravatar.com/avatar/fccd71b79b3571b459cdfe40e7bf5dd8?s=32&d=identicon&r=PG&f=1";
}
$scope.remove = function() {
$scope.imgShow = false;
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<img ng-src="{{imgSrc}}" ng-show="imgShow">
<hr/>
<button ng-click="display()" ng-hide="imgShow">display image</button>
<button ng-click="change()">change image</button>
<button ng-click="remove()">remove image</button>
</div>
If you want to manipulate the DOM in AngularJS you should use directives for this purpose.
You should avoid using jquery inside of your controllers and simply work with your model. Below is fileUpload directive that could help you to work with <input type="file"> in a more angularjs-way:
angular.module('myApp', [])
.controller('TestController', ['$scope', function ($scope) {
var ctrl = this;
ctrl.imageFile = null;
ctrl.clearFile = clearFile;
function clearFile(){
ctrl.imageFile = null;
}
$scope.$ctrl = ctrl;
}])
.directive('fileUpload', [function () {
return {
require: "ngModel",
restrict: 'A',
link: function ($scope, el, attrs, ngModel) {
function onChange (event) {
//update bindings with $applyAsync
$scope.$applyAsync(function(){
ngModel.$setViewValue(event.target.files[0]);
});
}
//change event handler
el.on('change', onChange);
//set up a $watch for the ngModel.$viewValue
$scope.$watch(function () {
return ngModel.$viewValue;
}, function (value) {
//clear input value if model was cleared
if (!value) {
el.val("");
}
});
//remove change event handler on $destroy
$scope.$on('$destroy', function(){
el.off('change', onChange);
});
}
};
}]);
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.angularjs.org/1.3.20/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="TestController">
<input type="file" file-upload ng-model="$ctrl.imageFile" />
<input type="button" ng-click="$ctrl.clearFile()" value="Reset" />
<div ng-if="$ctrl.imageFile">
{{$ctrl.imageFile.name}}<br />
{{$ctrl.imageFile.size}} byte(s)<br/>
{{$ctrl.imageFile.type}}
</div>
</div>
</div>
UPDATE: Also take a look at this useful reading.

Hide button and show after 3 seconds using AngularJS

I am just new to AngularJS and would like to ask how to show button after hiding it for 3 seconds when it is clicked.
Please see my code below.
<button class="btn btn-primary" ng-click="showDiv=true" ng-show="!showDiv">Button</button>
Thanks
Try use $timeout service
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $timeout) {
$scope.showDiv = true;
$scope.hide= function(){
$scope.showDiv = false;
$timeout(function () {
$scope.showDiv = true;
}, 3000);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<button class="btn btn-primary" ng-click="hide()" ng-show="showDiv" >Button</button>
</div>
Use the $timeout service in the controller and use it to unset showDiv.
app.controller('MyController', function ($scope, $timeout) {
$scope.showDiv = true;
$scope.enable= function () {
$scope.showDiv =false;
$timeout(function () { $scope.showDiv = true; }, 3000);
};
}
you can do this in this way also
angular.module("app",[])
.controller("ctrl",function($scope,$timeout){
$scope.showDiv=false;
$scope.timeout = $timeout;
$scope.saveFun = function(){
$scope.showDiv=true;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<button class="btn btn-primary" ng-show="!showDiv" ng-click="timeout(saveFun,3000);">Save</button>
</div>
Try using $timeout this may help you
JS code
var app = angular.module('myApp', []);
app.controller('ctrl', function($scope, $timeout) {
$scope.hide = false;
// function
$scope.hideMe = function() {
$scope.hide = true;
var sec = 3000; // 3 seconds
$timeout(function() {
$scope.hide = false
}, sec);
};
});
HTML
<div ng-app='myApp'>
<div ng-controller='ctrl'>
<button class="btn btn-primary" ng-click="hideMe()" ng-hide="hide">Button</button>
</div>
</div>
Here is Jsfiddle link

Ionic: Accessing from object in controller of the custom modal form

I've created a codepen to show the problem.
When the service appModalService is used, the vm object is directly replaced with the FormController object, so none of the attributes of vm is accessible in the template and the controller associated with the vm object becomes totally useless.
The discussion(reasoning) on the appModalService can be found in ionic form.
I've added the code here for reference. Any suggestions on fixing this issue ?
HTML:
<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Ionic modal service</title>
<link href="http://code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">
<script src="http://code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
</head>
<body ng-controller="AppCtrl as vm">
<ion-content padding="true" ng-class="{'has-footer': showFooter}">
<div class="row">
<div class="col">
<button ng-click="vm.showNonWorkingForm()" class="button button-assertive button-block">
Show Non Working Form (using appModalService)
</button>
</div>
</div>
<div class="row">
<div class="col">
<button ng-click="vm.showWorkingForm()" class="button button-assertive button-block">
Show Working Form (using ionic ModalService)
</button>
</div>
</div>
</ion-content>
<script id="non-working-form-modal.html" type="text/ng-template">
<ion-modal-view>
<ion-header-bar class="bar bar-header bar-positive">
<h1 class="title">Form</h1>
<button class="button button-clear button-primary" ng-click="vm.closeModal()">Close</button>
</ion-header-bar>
<ion-content>
<form novalidate name="vm.f" ng-submit="vm.submit()">
<div class="list">
<label class="item item-input">
<input placeholder="text" type="text" name="sometext" ng-model="vm.sometext" required>
</label>
</div>
<button type="submit" class="button button-block">
Submit
</button>
</form>
{{ vm }}
</ion-content>
</ion-modal-view>
</script>
<script id="working-form-modal.html" type="text/ng-template">
<div class="modal" ng-controller="WorkingCtrl as vm">
<ion-header-bar class="bar bar-header bar-positive">
<h1 class="title">Form</h1>
<button class="button button-clear button-primary" ng-click="closeModal()">Close</button>
</ion-header-bar>
<ion-content>
<form novalidate name="vm.f" ng-submit="vm.submit()">
<div class="list">
<label class="item item-input">
<input placeholder="text" type="text" name="sometext" ng-model="vm.sometext" required>
</label>
</div>
<button type="submit" class="button button-block">
Submit
</button>
</form>
{{ vm }}
</ion-content>
</div>
</script>
</body>
</html>
JS
angular.module('ionicApp', ['ionic'])
.controller('NonWorkingCtrl', ['$scope', 'parameters', function($scope, parameters) {
var vm = this;
/* placeholder for the FormController object */
vm.f = null;
vm.sometext = 'Added Some text';
vm.submit = function() {
if (vm.f.$valid) {
alert('NonWorkingCtrl Valid');
} else {
alert('NonWorkingCtrl InValid');
}
}
/* additional fields */
vm.field1 = 'field1';
vm.field2 = 'field2';
vm.field3 = 'field3';
vm.field4 = 'field4';
vm.field5 = 'field5';
vm.field6 = 'field6';
vm.field7 = 'field7';
}])
.controller('WorkingCtrl', ['$scope', function($scope) {
var vm = this;
/* placeholder for the FormController object */
vm.f = null;
vm.sometext = 'Added Some text';
vm.submit = function() {
if (vm.f.$valid) {
alert('WorkingCtrl Valid');
} else {
alert('WorkingCtrl InValid');
}
}
/* additional fields */
vm.field1 = 'field1';
vm.field2 = 'field2';
vm.field3 = 'field3';
vm.field4 = 'field4';
vm.field5 = 'field5';
vm.field6 = 'field6';
vm.field7 = 'field7';
}])
.controller('AppCtrl', ['$scope', 'appModalService', '$ionicModal', function($scope, appModalService, $ionicModal) {
var vm = this;
vm.showNonWorkingForm = function() {
appModalService.show('non-working-form-modal.html', 'NonWorkingCtrl as vm');
};
vm.showWorkingForm = function() {
$ionicModal.fromTemplateUrl('working-form-modal.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
$scope.modal.show();
});
$scope.closeModal = function() {
$scope.modal.hide();
$scope.modal.remove();
};
}
}])
.factory('appModalService', ['$ionicModal', '$rootScope', '$q', '$injector', '$controller', function($ionicModal, $rootScope, $q, $injector, $controller) {
return {
show: show
}
function show(templeteUrl, controller, parameters, options) {
// Grab the injector and create a new scope
var deferred = $q.defer(),
ctrlInstance,
modalScope = $rootScope.$new(),
thisScopeId = modalScope.$id,
defaultOptions = {
animation: 'slide-in-up',
focusFirstInput: false,
backdropClickToClose: true,
hardwareBackButtonClose: true,
modalCallback: null
};
options = angular.extend({}, defaultOptions, options);
$ionicModal.fromTemplateUrl(templeteUrl, {
scope: modalScope,
animation: options.animation,
focusFirstInput: options.focusFirstInput,
backdropClickToClose: options.backdropClickToClose,
hardwareBackButtonClose: options.hardwareBackButtonClose
}).then(function(modal) {
modalScope.modal = modal;
modalScope.openModal = function() {
modalScope.modal.show();
};
modalScope.closeModal = function(result) {
deferred.resolve(result);
modalScope.modal.hide();
};
modalScope.$on('modal.hidden', function(thisModal) {
if (thisModal.currentScope) {
var modalScopeId = thisModal.currentScope.$id;
if (thisScopeId === modalScopeId) {
deferred.resolve(null);
_cleanup(thisModal.currentScope);
}
}
});
// Invoke the controller
var locals = {
'$scope': modalScope,
'parameters': parameters
};
var ctrlEval = _evalController(controller);
ctrlInstance = $controller(controller, locals);
if (ctrlEval.isControllerAs) {
ctrlInstance.openModal = modalScope.openModal;
ctrlInstance.closeModal = modalScope.closeModal;
}
modalScope.modal.show()
.then(function() {
modalScope.$broadcast('modal.afterShow', modalScope.modal);
});
if (angular.isFunction(options.modalCallback)) {
options.modalCallback(modal);
}
}, function(err) {
deferred.reject(err);
});
return deferred.promise;
}
function _cleanup(scope) {
scope.$destroy();
if (scope.modal) {
scope.modal.remove();
}
}
function _evalController(ctrlName) {
var result = {
isControllerAs: false,
controllerName: '',
propName: ''
};
var fragments = (ctrlName || '').trim().split(/\s+/);
result.isControllerAs = fragments.length === 3 && (fragments[1] || '').toLowerCase() === 'as';
if (result.isControllerAs) {
result.controllerName = fragments[0];
result.propName = fragments[2];
} else {
result.controllerName = ctrlName;
}
return result;
}
}]);
#NEB I was having a similar issue around forms in ionic. I found my answer from DiscGolfer17 on the IonicForum, here
Basically, the ionic's <content> directive creates it's own isolated scope. As do forms and ionic's <ion-modal-view> directive I believe.
So to get your ng-click="vm.closeModal()" to work you need to chain a $parent in front of vm like this ng-click="$parent.vm.closeModal()"
This tells it to inherit it's parents $scope. Here is a working fork of your Plunk

text boxes changed to enable when click new in angularjs

I have form with bootstrap modal, in that modal has a text box and add email button. If you type proper email and click on add email button then the button will be changed to remove email button and text box mode set to disable mode and another new text. but when you click on remove email button all text boxes will be changed to in enable mode.
see my code here
My html code
<!doctype html>
<html ng-app="app" ng-controller="ModalDemoCtrl">
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script>
<script src="script.js"></script>
</head>
<div >
<script type="text/ng-template" id="myModalContent">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<li ng-repeat="item in items " ng-form="subForm">
<input type="text" name="name" ng-model="item.email" ng-disabled="isDisable(disbl,$index)" required ng-pattern="/^[_a-z0-9]+(\.[_a-z0-9]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/" ng-enter="addOrRemove($index,item.email)"/>
<span ng-show="subForm.name.$invalid || subFform.name.$pristine" style="color: red">Invalid email</span>
<button ng-disabled="subForm.name.$invalid || subFform.name.$dirty" ng-click="addOrRemove($index,item.email)" >{{item.value}}</button>
expression: {{subForm.name.$invalid}}
</li>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn btn-default" ng-click="open('lg')" >Large modal</button>
</div>
</body>
</html>
My script code
var app = angular.module('app', ['ui.bootstrap']);
//var ModalDemoCtrl = function ($scope, $modal, $log) {
app.controller('ModalDemoCtrl',['$scope', '$modal','$log','$rootScope',
function controller($scope, $modal, $log, $rootScope)
{
$scope.open = function (size) {
$scope.val = "";
var modalInstance = $modal.open({
templateUrl: 'myModalContent',
controller: ModalInstanceCtrl,
size: size,
backdrop: 'static',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
}]);
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope,$rootScope, $modalInstance) {
$scope.check2 = "hllo";
$scope.items = [
{
value: "Add email",
state: "1",
email: ""
}];
$scope.check1;
$scope.addOrRemove = function(indexSelected,rcvEmail)
{//alert($rootScope.email1);
if(!rcvEmail)
{
return
}
//console.log("just check email",rcvEmail);
//console.log("length of the object",$scope.items.length);
event.preventDefault();
if($scope.items[indexSelected].state == 1)
{
$scope.isDisable = function(value,index)
{
if(index <= indexSelected)
{
//console.log(index);
return value = "yes";
}
};
//console.log($scope.items[indexSelected].state);
$scope.items[indexSelected].value = "Remove email";
$scope.items[indexSelected].state = "0";
$scope.items[indexSelected].email = rcvEmail;
$scope.items.push({value: "Add email", state: "1"});
}
else
{
$scope.items.splice(indexSelected, 1);
$scope.isDisable = function(value,index)
{
console.log("indexes",index,"+",indexSelected);
/*index = index-1;
if(index <= $scope.items.length)
{
//console.log(index);
return value = "yes";
}
else
{
return value = "";
}*/
};
}
};
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
app.directive('ngEnter', function () {
console.log("directive checke");
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
see my code here
Set your ng-disabled to be
(items[$index].state == 0) ? true:false
instead of a function.

Angular Directive not updating

I am having an issue refreshing/updating an angular directive. Basically there is a Flag button which will make an async call to server and if it's successful, change the property userFlags which should disable the button and change it's text to "Flagged...".
Here is the directive:
app.directive('flagable', function() {
return {
restrict: 'E',
scope: { item: '=' },
templateUrl: '/Content/templates/flagable.tmpl',
controller: function($scope) {
$scope.flag = function () {
$scope.$apply(function () {
// ITS NOT GOING IN HERE!
//AJAX CALL HERE
model.$modelValue.userFlags = [];
Messenger().post("Your request has succeded! ");
});
};
}
};
});
Here is the template:
<div class="btn-group pull-right">
<button class="btn btn-small btn-danger" ng-disabled="{{item.userFlags != null}}"><i class="icon-flag"></i>
<any ng-switch="item.userFlags==null">
<any ng-switch-when="true">Flag</any>
<any ng-switch-when="false">Flagged...</any>
</any>
</button>
<button class="btn btn-small btn-danger dropdown-toggle" data-toggle="dropdown" ng-disabled="{{item.userFlags != null}}"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Inappropriate</li>
<li>Overpost</li>
<li>Spam</li>
</ul>
</div>
Interestingly enough, changing the controller logic to:
$scope.flag = function () {
$scope.item.userFlags = [];
Messenger().post("Your request has succeded! " + $scope.item.viewCount);
};
Causes for the button to refresh properly to "Flagged..." however, the ng-disabled its not making the button disabled! In firebug its showing that the ng-disabled property is set:
ng-disabled="true"
you need to assign scope item as '&'
var app = angular.module('app', []);
app.directive('flagable', function() {
return {
restrict: 'E',
scope: { item: '&' },
templateUrl: 'flagable.tmpl',
controller: function($scope) {
$scope.flag = function()
{
$scope.item.userFlags = [];
};
}
};
});
app.controller('appController', function($scope){
$scope.item ={};
//$scope.item.userFlags = null;
});
and ng-disable should have value like this because item object is already present in controller
ng-disabled="item.userFlags != null
Working demo present here
http://plnkr.co/edit/zvO24fb082hiyeinWmQi?p=preview
HTML PAGE:
<html ng-app="app">
<head>
<link data-require="bootstrap-css#2.3.2" data-semver="2.3.2" rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" />
<script data-require="angular.js#1.1.5" data-semver="1.1.5" src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<script data-require="jquery#*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="bootstrap#2.3.2" data-semver="2.3.2" src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="appController">
<h1>Hello Plunker!</h1>
<flagable item="item" flag="flag(item)"></flagable>
</body>
</html>
Controller and directive:
var app = angular.module('app', []);
app.directive('flagable', function() {
return {
restrict: 'E',
scope: { item: '=', flag: '&' },
templateUrl: 'flagable.tmpl'
};
});
app.controller('appController', function($scope){
$scope.item ={};
$scope.flag = function(item)
{
//call service to set flag here
item.userFlags = [];
};
});
template page
<div class="btn-group pull-right">
<button class="btn btn-small btn-danger" ng-disabled="item.userFlags != null"><i class="icon-flag"></i>
<any ng-switch="item.userFlags==null">
<any ng-switch-when="true">Flag</any>
<any ng-switch-when="false">Flagged...</any>
</any>
</button>
<button class="btn btn-small btn-danger dropdown-toggle" data-toggle="dropdown" ng-disabled="item.userFlags != null"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Inappropriate</li>
<li>Overpost</li>
<li>Spam</li>
</ul>
</div>

Resources