How can I can get btnDisabled to change the data-ng-disabled in the immediate function scope but inside my ajax success scope nothing is playing nicely. How to I get my button to disable?
JS
.controller('CouponCtrl', function($http, $scope) {
$scope.btnDisabled = false;
// $scope.btnDisabled = true; // this works fine too
$http.jsonp("someurl?_jsonp=JSON_CALLBACK").success(function(){
$scope.btnDisabled = true; // does not work
console.log("I see this so why doesn't my button disable?");
// $scope.$digest(); // tried this too but I'm told digest is already running
}
}
HTML
<button data-ng-disabled="{{ btnDisabled }}" class="button button-block green">redeem coupon</button>
NOTE
I've noticed that none of my two-way data binding works when I update a variable via the ajax success scope. Is there a way to overcome that?
ngDisabled expects an expression, not a string (interpolation always outputs string values):
<button data-ng-disabled="btnDisabled"
class="button button-block green">redeem coupon</button>
Working Plunker
Change
data-ng-disabled
to
ng-disabled
Related
html
<button class="btn btn-primary" ng-click="tasks.passivate()">
Passivate <i class="fa fa-spinner fa-spin" ng-if="tasks.passivating"></i>
</button>
task.controller
function passivate() {
console.log('passivate');
vm.passivating = true;
return taskService
.passivate(vm.task.id)
.then(function (task) {
vm.passivating = false;
})
.catch(alertError);
}
The button does not work, passivate does not appear in the console.
When referencing something from the controller in the view, you have to use the $scope. Your function definition should be:
$scope.tasks.passivate = function() {
//...
}
your button, I believe is part of the view which is now bound to a controller. The controller creates a scope object which actually glues your view and the controller. So if you want to invoke a function from the view it should have the scope reference. Hence $scope should be used:-
$scope.tasks.passivate = function(){
//----your logic goes here.
}
Its good to see that you are using tasks.passivate as it will save your from prototypal inheritance. To know more:- Click here
I want not to show ui.bootstrap popover by using popover-is-open directive. For example, in template:
<button class="fa fa-link add-link"
uib-popover="popover"
popover-is-open="isOpen"> Show popover </i>
And in controller:
angular.module('demoModule').controller('PopoverDemoCtrl', function ($scope) {
$scope.isOpen = false;
});
See plunkr
I am expecting that popover should never be opened, but it opens on click on it. It seems that popover-is-open affects only first angular compiling. Any ideas?
upd: Actually, i want not to show popover only in some cases, in other cases it should be shown. For example, i have download-dialog popover and i want to show it only if size of file is greater than some limit.
The popover-is-open is only for the initial behavior, i.e. if it evaulates to true, then the popover opens instantly even without a click. If you change the value of isOpen to true in your plunkr, you see that (my example plunkr).
What you want is the popover-enable attribute:
<button class="fa fa-link add-link"
uib-popover="popover"
popover-enable="isOpen">Show popover</button>
Update for the question update:
You are free to evaluate any boolean expression in the popover-enable attribute instead of the static isOpen which always evaulates to false in your example.
I have created an advanced plunkr to show that:
<input type="text" ng-model="downloadSize">
<button class="fa fa-link add-link"
uib-popover="popover"
popover-enable="isOpen()">Show popover</button>
with the controller code
$scope.isOpen = function() { return $scope.downloadSize > 100; }
You have a new text box where you can enter a number to simulate the download size. When it gets > 100, the popup will be enabled.
In order to handle the open state whit the popover-is-open value you must set popover-trigger="none" or maybe popover-trigger="'none'". As it says in the docs
Using the 'none' trigger will disable the internal trigger(s), one can
then use the popover-is-open attribute exclusively to show and hide
the popover.
Use
$scope.$apply(function () {
$scope.isOpen = false;
});
method for applying this property
I have made a simple pop up window by using ui.bootstrap but I can't seem to make the OK and CLOSE button to work. What am I missing in this sample codes?
Here is the sample code from plunkr
Thank you
**added exact code image
close and dismiss are methods of $modalInstance object returned by $modal.open:
$scope.open = function() {
$scope.$modalInstance = $modal.open({
scope: $scope,
templateUrl: "modalContent.html",
size: '',
})
};
$scope.ok = function() {
$scope.$modalInstance.close();
};
$scope.cancel = function() {
$scope.$modalInstance.dismiss('cancel');
};
One more problem with your code is that you need to specify scope: $scope in modal config. This is necessary if you want the scope inside modal template to be a child scope of the one, where you are defining ok/cancel methods.
Fixed demo: http://plnkr.co/edit/Y5s4yPm1TZB8S9nfO5CA?p=preview
I updated your code with a working version
http://plnkr.co/edit/iM5o0le3OioqxHBNF3d1?p=preview
There are a few things wrong with your code.
$modal is a factory, you can't call $modal.close()
You would need to do something like:
this.modal = $modal(....)
this.modal.close();
Still, even if you did this in your controller, your modal view does not have access to the scope.
The solution in the forked plunk I offer is to use
ng-click="$parent.$close()"
There are several ways as explained before and it depends in which context you need to use it.
For example if the modal is just a notification, there's no need to use functions for the buttons OK or CANCEL, just using $dismiss() or $close() in the ng-click of the buttons located in the modalContent.html file will be enough.
Here is also an updated plunker
http://plnkr.co/edit/OfCGJX?p=preview
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$close()">OK</button>
<button class="btn btn-warning" ng-click="$dismiss()">Cancel</button>
</div>
I'm trying to use AngularJS 1.3.0's new $rollbackViewValue() method in ngModelController to cancel changes to a form in a modal popup or persist them when I close the modal. I'm using BootstrapUI for the $modal service.
I think I'm on the right track, but there is something that isn't quite working properly:
In my controller, I've got:
$scope.updateCharge = function (charge) {
var scope = $scope.$new();
scope.charge = charge;
var modalInstance = $modal.open({
templateUrl: 'client/app/views/providers/charges/updateCharge.html',
scope: scope
});
modalInstance.result.then(function () {
scope.charge.$save({providerId: providerId, chargeId: charge.id});
});
};
In my template, I have the following:
<form name="form" novalidate ng-model-options="{updateOn: 'save', debounce: {'save': 0 }}" class="form-horizontal" role="form">
<div class="modal-body">
<div class="form-group">
<label class="col-sm-3 control-label" for="chargeName">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" required ng-model="charge.code" id="chargeName"/>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-disabled="form.$invalid" ng-click="form.$broadcast('save'); $close()">Update</button>
<button class="btn btn-warning" ng-click="form.$rollbackViewValue(); $dismiss('cancel')">Cancel</button>
</div>
</form>
Generally speaking, this seems to work. When I click on cancel, my changes are reverted. When I click on Update, the modal closes but I do not see my updates in the scope.charge object.
I would have expected that my scope.charge object would be updated prior to the modal closing.
Am I using the ng-model-options incorrectly?
If I add a separate 'Apply' button that only does a form.$broadcast('save'), I see my scope object properly updated. So I am presuming that my $close() is being called prior to the event being processed by the ng-model-options. How can I avoid this race condition?
You can to use the $rollbackViewValue() method to revert changes but I think that is not the intention.
$rollbackViewValue(); Cancel an update and reset the input element's
value to prevent an update to the $modelValue, which may be caused by
a pending debounced event or because the input is waiting for a some
future event.
If you have an input that uses ng-model-options to set up debounced
events or events such as blur you can have a situation where there is
a period when the $viewValue is out of synch with the ngModel's
$modelValue.
In this case, you can run into difficulties if you try to update the
ngModel's $modelValue programmatically before these debounced/future
events have resolved/occurred, because Angular's dirty checking
mechanism is not able to tell whether the model has actually changed
or not.
The $rollbackViewValue() method should be called before
programmatically changing the model of an input which may have such
events pending. This is important in order to make sure that the input
field will be updated with the new model value and any pending
operations are cancelled.
The normal use case is to copy the model, optionally to persist the model and, if all is ok, refresh the model.
_this = this;
this.edit = function() {
this.modelToEdit = angular.copy(this.originalModel);
}
this.save = function () {
service.save(modelToEdit).then(function(savedModel) {
_this.originalModel = savedModel;
});
}
Or you can backup the model and restore when cancel
_this = this;
this.edit = function() {
this.backupModel = angular.copy(originalModel);
}
this.cancel = function() {
this.originalModel = this.backupModel;
}
this.save = function() {
service.save(this.originalModel).then(function(data) {}, function(error) {
_this.originalModel = _this.backupModel;})
}
I can see a few problems with your code:
ngModelOptions.updatedOn is meant to be a DOM event, i.e. click, blur, mouseenter, mouseover, etc,
The form controller does NOT have a $broadcast method, so it's never emitting an event.
I think the fact that it sort of works is because there is not type="button" on the <button> so they are considered as "submit" inside the form. And the model is updated because of that.
I suggest you use a simplified version, and
remove the ng-model-options from the form.
add a type="submit" to the Update button, and remove the form.$broadcast
add a type="button" to the Cancel button.
Am not sure how it would work with the modal, but here's a plunkr with ng-if: http://plnkr.co/edit/m37Fd0NybpnfslNkvJnO
I did not end up using any of the options suggested as answers, because the reality is, angular 1x has no "proper" way of doing what I want. Angular uses 2way binding, and yes I can write fancy directives to make life easier but infact it just makes the html looks even more complicated.
I settled with the suggested way as per many threads on the forum and that is to use angular.copy and then use the cloned model in your html. When you submit changes, set the cloned model to the original model.
There was heaps of examples on here on how to use angular.copy. And it works well.
I have ngClick and ngClass on an element duplicated by ngRepeat:
<li
ng-class="{'active': $parent.mem.A == $key, 'not-active': $parent.mem.A && $parent.mem.A != $key}"
ng-repeat="($key, A) in As"
ng-click="$parent.mem.A = $key">
Inside the li I have a button that changes the value of $parent.mem.A onClick:
<button ng-click="$parent.mem.A = $parent.findInHash('prev','A')">Activate previous</button>
findInHash() returns the expected value, and when I step through angular, the value in $scope.$apply() from ngEventDirective is correct; but somewhere it's getting lost.
fiddle
in your code all ng-click are executed when you click on the button
you just need to stop the event propagation like the following sample
$scope.findInHash = function ($event, dir, attr) {
$event.stopPropagation();
$event.preventDefault();
...
<button ng-click="$parent.mem.A = $parent.findInHash($event,'prev','A')">...
When you click on the button, the click event is propagated to the li element and its ng-click is executed as well.
In ng-click the $event variable is available so you can easily use it to stop event propagation:
<button ng-click="$parent.mem.A = $parent.findInHash('prev','A');$event.stopPropagation();">Activate previous</button>