How can I prevent ng-model from being changed in select based on result of function? - angularjs

I have a select drop down menu populated with ng-options. I want to create a pop-up that will require the user to confirm they want to change the selected option before continuing.
So far, I have tried using an ng-change, but that doesn't work because you can't prevent the change (for the purposes of my app, I cannot simply put the value back to what it was before the change in an ng-change function). I have tried ng-click, but this fires when the user clicks on the select box, whereas I want this to fire when the user actually selects one of the options from the select box for UI purposes. I have investigated ng-model-options, but my problem is I cannot seem to get an event to fire when an option is selected.
Code below demonstrating what this select looks like:
<select ng-model='uiConfig.selectedInteractionType' ng-options='interactionType for interactionType in uiConfig.interactionTypes'></select>

I had this exact same requirement, albeit for a different element. I had a button that was really an anchor tag where I passed in some values, including a URL when the user clicked the button. I then needed to open an $mddialog modal and let the user cancel or click continue to send them to a redirected site.
What you need is a directive here. Put the value(s) in $scope. I used attributes for this:
restrict: 'A',
and then in my link function I used
attributes.$observe
to pull in my values.
Then use something like this in your directive function:
element.on('click' function ($event) {
$event.preventDefault(); //To stop the event flow.
$mdDialog.show({
templateUrl: "path to your modal html document",
controller: myController,
clickOutsideToClose: true,
locals:{
href: $scope.href,
myValue: $scope.myValue
}
Using $locals allows you to pass in the values to the directive.

Related

angular view not reflecting controller

This is an angular 1 app.
I have a directive that looks like this:
function addLiquidity() {
return {
restrict: 'E',
scope: {
expanded: '='
},
templateUrl: 'liquidity.html',
controller: 'addLiquidityCtrl'
};
}
And the html that looks like this:
<add-excess-liquidity expanded="addExpanded"></add-excess-liquidity>
In another html I have this:
expanded: {expanded}
This is false by default thanks to the controller that in its relevant part contains this:
$scope.addExpanded = false;
Now, when clicking a button to show form for adding new stuff, "addExpanded" is set to true.
When then the button to actually save the form is clicked "addExpanded" is set to false again:
$scope.addExpanded = false;
I can see in the controller that that function is called and that addExpanded behaves correctly in the controller.
Actually, it behaves correctly in the view too. So the value in html:
expanded: {expanded}
reflects the value in the controller.
However, as soon as I switch to another tab (this app is using nav-tabs) and come back to the tab I was before, then the value in html is not reflecting the controller anymore(which is still doing its job like before, going through the same steps as before, included setting the "expanded" to false).
I tried forcing view update with both timeout and "apply" but didn't help. Also, it seems somwehere else an apply is fired at the end of every function.
I really don't understand what's wrong here. Where should I look? Something happen (I guess) when leaving the tab the first time. But so many things happen so it is not easy to debug. Any clue anybody?
EDIT
I added a watch like this:
$scope.$watch( 'addExpanded',
function(newValue, oldValue){
console.log('addExpanded Changed');
console.log(newValue);
console.log(oldValue);
}
);
First time I go to the tab then it will print to console. I then leave the tab, then come back to it. And this time, when clicking on button, nothing is printed to the console.
Roughly, what happens when I change tab is that the div containing the tab-content is set to "display:none/block" (I guess) as it is pure css that is showing tab content upon selection.
In the main controller a few things are done depending on which tab was selected, but I cannot see things that would "destroy" the connection between the GUI and the controller/directive.
Also, each time I go to that tab, I see that the javascript connected to the directive is initiating. And the variable "expanded" is reset to false.
The issue is that, for some reason, the connection between javascript and the GUI is in some way "lost" when visiting the tab the second time (and for all the future until I refresh the page).

How to detect focus or touched on md-contact-chips in angularjs?

I'm trying to detect if a user has focus on md-contact-chips.
On all other controls it can easily be detected inside a form via formName.controlName.$touched
Here is the CodePen
Thanks in advance.
I think the md-contact-chips are not a form element or a link, and thus don't have the ability to gain / lose focus. (source: AngularJS docs on ngFocus) You could bind ng-click on md-contact-chips though.
Example CodePen which binds ng-click and receives the model value of the clicked md-contact-chips.
As you can see I added a ng-click to the md-contact-chips element:
<md-contact-chips ng-click='ctrl.chipFocus(ctrl.contacts)'
And I added the chipFocus method to the AngularJS controller:
self.chipFocus = function(contact) {
alert('focus gained');
console.log(contact);
//you could do something with contact here
};
This might be the answer to your question, but if you want the chips input to add on loseFocus, or tab, you can add this:
md-add-on-blur="true"
Reference: https://github.com/angular/material/pull/9095

How to design angular app with multiple models and select fields

What I'm trying to build is a SPA containing multiple selects on one page, where each select has it's own model. Choosing different options in the select boxes may show/hide other fields on the page and modify data for other selects (load different sets). Finally options in two selects may change the url (so when page is loaded with a proper address, those two options will be preselected).
Now I'm wondering what'll be the best approach here.
First. Is it worth to switch to ui-router in this case ?
Second. I need to write a custom directive for this select, that will have the following functionality
load data collection
display data and remember selection
reload it's data collection when other select triggered it
reload data for other selects
Now I've written directives before but never anything this (I think) complex. That's why few questions come to my mind.
How can I bind different data to my directive ?
Should this be just a single massive complex directive or divide it to smaller parts (like one directive for showing closed select box and another one to show the list and so on) ?
How can I trigger event when data should be changed and listen to a similar event from another select. Via controller ?
Thanks in advance for all your help.
What I can suggest is keep it MVC. Here is one of the solution -
Create a controller to store model data (here $scope.selectOptions inside controller)
Pass this values to 'select directive' instance to display
Whenever user select the value in directive, pass that selected value to controller (lets say in controller $scope.selectedValue is holding that value)
In controller add $watch on $scope.selectedValue and in its callback call for different data set for another select option. (lets say storing that data set in $scope.anotherSelectOption )
Pass this $scope.anotherSelectOption to '2nd directive' instance
Whenever user select the value in 2nd directive, pass that selected value to controller (lets say in controller $scope.anotherSelectedValue is holding that value)
In controller add $watch on $scope.anotherSelectedValue and in its callback change url thing you want to do
Here's your HTML will look like -
<div ng-controller="MyCtrl">
<select-directive selection-option="selectOptions", selected-option="selectedValue"> </select-directive>
<select-directive selection-option="anotherSelectOptions", selected-option="anotherSelectedValue"> </select-directive>
</div>
Here's your controller, it will look something like this -
yourApp.controller('MyCtrl', function($scope) {
$scope.selectOptions = []; // add init objects for select
$scope.selectedValue = null;
$scope.$watch('selectedValue', function() {
// here load new values for $scope.anotherSelectOptions
$scope.anotherSelectOptions = [] // add init objects for select
$scope.anotherSelectedValue = null;
});
$scope.$watch('anotherSelectedValue', function() {
// here add code for change URL
});
});
Here's your directive scope is
yourApp.directive('selectDirective', function() {
return {
templateUrl: 'views/directives/select.html',
restrict: 'E',
scope: {
selectionOption: '=',
selectedOption: '='
}
};
});

Angular - trigger unsavedChanges directive when user clicks on a non-submit button

How do I trigger the angular-unsavedChanges directive to check to see if a form is dirty when a user clicks on a button in a form that is not a submit button? I want a message to pop-up if the user clicks on a button that would navigate them to a different page, if changes have been made to the current form. It seems to work on a refresh and a link to a different page, but not a button that will be loading a different template. TIA.
Without sample code, I can't be sure, but I think that since the directive you are using specifically binds to the $locationChangeStart event, you could try the following :
configure your $routeProvider to monitor url changes ( I suppose it is already what you are doing with your SPA, but correct me if I'm wrong)
$routeProvider
.when('/otherPage', {
templateUrl: 'partials/myOtherPage.html',
controller: 'OtherCtrl',
})
Use you the ng-click on your button to call the $location service (don't forget to pass it to your controller)
$scope.navigateToOtherPage = function() {
$location.path('/otherPage');
}
Since $location fires the $locationChangeStart event right before changing the url, your directive should be able to capture it and proceed with its expected behaviour.

Opening angular-ui-bootstrap modal from javascript

I am trying to open the modal dialog from javascript when a certain condition is met. The example shown here http://angular-ui.github.io/bootstrap/ invokes the modal on ng-click.
How do I achieve showing modal when a certain condition is met?
Thanks
Additional Info
Sorry didn't mean to create confusion. I am going to clarify a little bit more by saying what I meant by "certain condition". The scenario is the user will search for customer by name and will get a list of customers back matching with the search string. The user then clicks on any one of the customer row to get more detail information.
When clicked the code control is handed off to Controller (It's an ASP.Net MVC app) which will then go through other classes and finally get data of the customer from database. It will then populate a boolean property called spouseNotFound. It then returns the JSON back to angularjs controller. Now assume that if this particular customer does not have spouse I want to show a modal saying that "Spouse not found".
So, no, I don't want the modal to be invoked on an event, rather than on business rule condition.
Hope that helps to understand things clearly.
Straight from the documentation.
$modal is a service to quickly create AngularJS-powered modal windows. Creating custom modals is straightforward: create a partial view, its controller and reference them when using the service.
Example plnkr. (http://plnkr.co/edit/?p=preview)
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
If anyone needs an easy approach to showing Bootstrap Modals with AngularJS, then you can simply use the following approach. It worked well for me:
var element = angular.element('#myModal');
// Open dialog
element.modal('show');
// Close dialog
element.modal('hide');
What you may be looking for is a $watch on your scope. This will allow you to monitor a variable, and when the value is what you want, then launch the modal as Nix describes.
$scope.$watch('entities', function(){
if($scope.entities[0].checked && $scope.entities[1].checked){
alert("If I were bootstrap, I'd be launching a modal right now!");
};
}, true);
A jsfiddle: http://jsfiddle.net/HB7LU/1636/

Resources