Using $watch for two variables angularjs - angularjs

I have a pop up screen in which a user require to select from two drop down lists.
After the selections were completed i return the selections to the service and save them in an object.
app.service('OriginalService', [ '$modal',
function ($modal) {
var that = this;
this.filtersMananger = { // my-ng-models for the two drop-down-lists
firstFilter: "",
secondFilter: ""
};
this.openDialog = function(){
var modalInstance = $modal.open({
templateUrl: 'ModalScreen.html',
controller: 'ModalController',
resolve: {
filtersManagerObject: function () {
return that.filtersMananger;
}
}
});
modalInstance.result.then(function (filtersMananger) {
that.filtersMananger.firstFilter = filtersMananger.selectedFirstFilter;
that.filtersMananger.secondFilter = filtersMananger.selectedSecondFilter;
}, function () {
});
};
}
]);
The pop up html:
<div class="data-filters-container">
<div class="data-filter">
<label for="filter-data-drop-down">FIRST FILTER</label>
<select name="filterDataDropDown" ng-model="filtersMananger.selectedFirstFilter" ng-options="filter.value as filter.name for filter in filterDropDownItems"></select>
</div>
<div class="data-filter col-xs-4">
<label for="filter-data-drop-down">SECOND FILTER</label>
<select name="filterDataDropDown" ng-model="filtersMananger.selectedSecondFilter" ng-options="filter.value as filter.name for filter in filterDropDownItems"></select>
</div>
However, this change is important and i have to call to the controller which knows many other services to send them information regarding this change.
In order to do it i used a watch function in the controller:
$scope.$watch('OriginalService.filtersMananger.firstFilter + OriginalService.filtersMananger.secondFilter', function (newVal, oldVal) {
if (newVal !== oldVal) {
DO SOME LOGIC
}
});
I compare between newVal and oldVal because when the app is uploaded the event is called and we enter to this function.
The problem is that the newVal is contains only the value of the secondVariable.
Is there any idea why the newVal is not contains also the first variable?

Use $watchCollection:
$scope.$watchCollection('[serviceName.Object.firstVariable,serviceName.Object.secondVariable]', function (newValues, oldValues) {
});
Or if you're using angular 1.3 use $watchGroup:
$scope.$watchGroup(['serviceName.Object.firstVariable','serviceName.Object.secondVariable'],function(newValues, oldValues){
})

You could also use ng-change on your select.
The ng-change will call a function that do your logic
<div class="data-filters-container">
<div class="data-filter">
<label for="filter-data-drop-down">FIRST FILTER</label>
<select name="filterDataDropDown" ng-change="checkFilterOne()" ng-model="filtersMananger.selectedFirstFilter" ng-options="filter.value as filter.name for filter in filterDropDownItems"></select>
</div>
<div class="data-filter col-xs-4">
<label for="filter-data-drop-down">SECOND FILTER</label>
<select name="filterDataDropDown" ng-change="checkFilterTwo()" ng-model="filtersMananger.selectedSecondFilter" ng-options="filter.value as filter.name for filter in filterDropDownItems"></select>
</div>
It will call the function when your model will change that is like a $watch.

Related

How can I access controller method on a modal instance controller on AngularJS?

Can you help me with this? I am trying to access the function on my parent/main controller from the template created on the modal instance but I couldn't access it directly. Can you help me with this?
Here's my code:
Here's the function for accessing and showing the modal:
openQuestionModalForm() {
let ctrl = this;
var modalInstance = ctrl.$modal.open({
templateUrl: 'questionModal.tmpl.html',
scope: this.$scope,
controller: ['$modalInstance', function($modalInstance) {
this.parentController = ctrl;
this.modalOptions = {
mode: 'add',
actionType: 'add'
}
console.log(this.Questionnaire_formController);
//this.modalOptions.data = angular.copy(data);
// this.modalOptions = {
// mode: mode,
// id: id,
// data: angular.copy(data),
// actionType: mode //set to mode temporarily should be ActionType
// }
this.close = $modalInstance.close;
}],
size: 'small',
controllerAs: '$ctrl',
windowClass: 'addeditcourseware-modal'
});
modalInstance.result.then(function(result) {
try {
console.log('*-----*', result);
} catch(e) {
console.log('Error!');
}
})
}
This is triggered by this function and I attached this event on a button
openAddEditCoursewareModal(mode, id, data, actionType) {
let ctrl = this;
if(ctrl.QuestionsStore.questionnaireType == 'Questionnaire') {
this.openQuestionModalForm(); //shows my modal based on the condition
....
<div class="row">
<div class="columns title-box move-right">
<p class="title">Questions</p>
<div class="button_link">
<button class="button-primary button-default" ng-click="$ctrl.openAddEditCoursewareModal('add')">Add Question</button>
</div>
</div>
</div>
Now here's the part where I am calling the function on my parent/main controller.
<label class="stacked">
Question Type:
<select name="question_type" class="form-field" id="questionType" ng-model="$ctrl.questionModal.data.attributes.question_type" ng-change="$ctrl.getSelectedQuestionType()" ng-required="true">
<option value="single">Single</option>
<option value="multiple">Multiple</option>
<option value="true_or_false">True or False</option>
<option value="free_text">Free Text</option>
</select>
</label>
I am calling the function getSelectedQuestionType on the onchange event. But the result on the console is undefined.
Can you help me with this?
You could pass the function reference through a resolve block and then access it in your modal controller, as such:
modalInstance = ctrl.$modal.open({
...
resolve: {
'getSelectedQuestionType': function () {
return ctrl.getSelectedQuestionType;
}
},
controller: ['$modalInstance', 'getSelectedQuestionType', function($modalInstance, getSelectedQuestionType) {
// Bind to controller so that you can call it via $ctrl.getSelectedQuestionType in your view
this.getSelectedQuestionType = getSelectedQuestionType;
}
...
});
Hope this helps :)

Factory value not updated in model ...what I am doing wrong?

I am new to angular-js. I have two controllers (welcomeContoller,productController) and both handling the same model within the factory.
When the model getting updating by one controller(productController) it should reflect the update in another controller. (welcomeContoller)
But its not happening now.
HTML code :
<body ng-app="myApp">
<div ng-controller="welcomeContoller">
{{totalProductCnt}}
</div>
<div ng-controller="productController">
<div class="addRemoveCart">
<span class="pull-left glyphicon glyphicon-minus" ng-click="removeProduct()"></span>
<span class="pull-right glyphicon glyphicon-plus" ng-click="addProduct(1)"></span>
</div>
</div>
JS code
var myApp = angular.module("myApp", ['ui.bootstrap']);
myApp.factory("productCountFactory", function() {
return {
totalProducts:0
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory)
{
$scope.totalProductCnt = productCountFactory.totalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.totalProducts++;
alert(productCountFactory.totalProducts);
};
$scope.removeProduct = function() {
if(productCountFactory.totalProducts >=1)
productCountFactory.totalProducts--;
alert(productCountFactory.totalProducts);
};
});
Even after the addProduct is called the totalProductCnt is displaying as zero. I want to display the value for each increment.
Plunkr Link
Put the factory object reference on scope:
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.productCountFactory = productCountFactory;
});
Watch the property of the object.
{{productCountFactory.totalProducts}}
The DEMO on PLNKR.
By putting a reference on scope, on every digest cycle the watcher looks up the value of the property and updates the DOM if there is a change.
The totalProductCnt from your welcomeController isn't updated because it is assigned only once when the controller is created.
You can use several solutions to refresh the displayed value. Use a getter for your totalProducts in the factory :
myApp.factory("productCountFactory", function() {
var totalProducts = 0;
return {
getTotalProducts: function() {
return totalProducts;
},
addProduct: function() {
totalProducts++;
},
removeProduct: function() {
totalProducts--;
}
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.getTotalProducts = productCountFactory.getTotalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.addProduct();
};
$scope.removeProduct = function() {
if (productCountFactory.getTotalProducts() >= 1)
productCountFactory.removeProduct();
};
});
And update the view accordingly:
<div ng-controller="welcomeContoller">
{{getTotalProducts()}}
</div>
Plunkr Link

Display dropdown on tick of checkbox

// I have written java code to fetch data from mongo-db. What i need to do is on tick of checkbox button i have to display those data in drop-down menu using angular-js and bootstrap. Nothing is happening after doing these code.
.html page
<div ng-controller="release">
<div class="col-md-2 col-centered col-fixed">
<label for="cloneRelease" translate="release.form.cloneRelease">CloneRelease</label>
</div>
<div>
<input type="checkbox" ng-model="ticked">
<div class="dropdown-menu" ng-repeat="release in releaseName" ng-show="ticked">{{release.name}}</div>
</div>
</div>
controller.js
releaseApp.controller('release', function($scope, $location, $http, ReleaseNameService){
$scope.releaseName = [];
init();
function init(){
ReleaseNameService.getReleaseName().then(function(data){
$scope.releaseName = data;});
console.log('inside controller: '+$scope.releaseName);
}
});
service.js
releaseApp.factory('ReleaseNameService', function($http){
var releaseName = [];
var factory = {};
factory.getReleaseName = function(){
return $http.get('release/fetchAllReleaseDetails').then(function(response){
releaseName = response.data;
console.log('inside service method'+ releaseName);
return releaseName;
});
};factory;
});
It is simple, u need to bind checkbox with ng-model:
<input type="checkbox" ng-model="ticked">
If its ticked $scope.ticked return true, else return false. If true show data, if false hide it (with ng-show)
Here is an example in jsFiddle without css ofc.
http://jsfiddle.net/RLQhh/2282/
UPDATE:
recreateing case with service.
service.js
app.factory('dataService', function ($http) {
var dataObject= {
async: function () {
var promise = $http.get('data/').then(function (response) {
return response;
});
return promise;
}
};
return dataObject;
})
controller.js
$scope.dataTest = [];
$scope.ticketed = false;
var getData = function(){
dataService.async().then(function (d) {
$scope.dataTest = d.data;
});
}
getData();
html
<input type="checkbox" ng-model="ticketed">
<div ng-show="ticketed" ng-repeat="dat in dataTest">
{{dat.name}}
</div>
...this is tested case so it should work with yours
You can make a REST call to fetch the data from your java function and store it in scope.Then you can use ng-repeat to display data in dropdown.
Here is a very good article on how to do it.
http://www.infragistics.com/community/blogs/dhananjay_kumar/archive/2015/06/29/how-to-work-with-the-bootstrap-dropdown-in-angularjs.aspx

How to change select functions in Angular Directive?

http://plnkr.co/edit/pJRzKn2v1s865w5WZBkR?p=preview
I have a large select dropdown form which is repeated in 2 places. The only thing that changes is the first select tag, which has a different function.
<!--
On simple, change ng-change function to functionOne
On advanced, change ng-change function to functionTwo
-->
<select name="name1" ng-change="functionOne('function1')" id="the-id-1">
<select name="name2" ng-change="functionTwo('function2)" id="the-id-2">
<option value="aaa">aaa</option>
<option value="bbb">bbb</option>
<option value="ccc">ccc</option>
</select>
I tried using ng-hide ng-show however there must be a different way to accomplish this.
var app = angular.module('myApp', [])
.directive('termsForm', function() {
return {
templateUrl : "termsForm.html",
restrict : "E",
scope : false,
controller : 'TermsFormController'
}
})
.directive('selectOptions', function() {
return {
templateUrl : "form.html",
restrict : "E",
scope : false
}
})
.controller('TermsFormController',
['$scope',
function($scope) {
var vs = $scope;
vs.hello = "This is the form.";
vs.showingSimple = true;
vs.showingAdvanced = false;
vs.showForm = function(type) {
if (type === 'simple') {
vs.showingSimple = true;
vs.showingAdvanced = false;
} else if (type === 'advanced') {
vs.showingSimple = false;
vs.showingAdvanced = true;
}
}
vs.functionOne = function(msg) {
alert(msg);
}
vs.functionTwo = function(msg) {
alert(msg);
}
}]);
termsForm.html
<ul class="nav nav-tabs">
<button class="btn btn-info" ng-click="showForm('simple')">Simple</button>
<button class="btn btn-info" ng-click="showForm('advanced')">Advanced</button>
</ul>
<p>The select:</p>
<div ng-show="showingSimple" class="simple-form">
<p>Simple</p>
<select-options></select-options>
</div>
<div ng-show="showingAdvanced" class="advanced-form">
<p>Advanced</p>
<select-options></select-options>
</div>
You already have a directive created for your select, that gets you half way there. Now you just need to pass the function in through whats known as the isolated scope.
.directive('selectOptions', function() {
return {
templateUrl : "form.html",
restrict : "E",
scope : {
changeFunc: '&'
}
}
})
This allows you to pass in the function you want to call on the ng-change event:
<select-options changeFunc="function1"></select-options>
<select-options changeFunc="function2"></select-options>
And then in your form.html you simply put
<select name="name2" ng-change="changeFunc()" id="the-id-2">
This way you are basically passing the funciton in as a parameter. Read this blog for a great guide on isolated scopes.
I would just refactor your markup and controller to adapt based on the simple/advanced context.
In your controller, you'd expose a 'generic' on change function for the dropdown, first...
(function () {
'use strict';
angular.module('app').controller('someCtrl', [someCtrl]);
function someCtrl() {
var vm = this;
vm.isSimple = true;
vm.nameChange = function () {
if(vm.isSimple)
functionOne('function1');
else
functionTwo('function2');
}
// Other things go here.
}
})();
...Then, on your view, your select would change to this*:
<select id="someId" name="someName" ng-change="vm.nameChange()" />
*: Assuming you're using controllerAs syntax, that is. If you're not, don't prepend the vm. on the select.

AngularJS UI Modal and select doesn't update the scope values

I am having a lot of trouble trying to save values from the modal component available in Angular UI.
Here is the page controller that calls the modal dialog
$scope.sourceSchema = [];
$scope.targetSchema = [];
$scope.apiDefinition = [];
$scope.availableSchemas = availableSchemas.get();
$scope.addComponent = function (type) {
$scope.$broadcast('addComponent', [type]);
var templateUrl = "";
var controller = null;
var resolve = null;
var componentSchema = [];
switch (type) {
case "sourceSchema":
templateUrl = 'source-schema.tpl.html';
controller = 'SourceCtrl';
componentSchema = $scope.sourceSchema;
break;
case "targetSchema":
templateUrl = 'target-schema.tpl.html';
controller = 'TargetCtrl';
componentSchema = $scope.targetSchema;
break;
case "api":
templateUrl = 'api.tpl.html';
controller = 'SourceCtrl';
componentSchema = $scope.apiDefinition;
break;
}
var modalInstance = $modal.open({
templateUrl: templateUrl,
controller: controller,
resolve: {
existingSchemas: function () {
return $scope.availableSchemas;
}
}
});
modalInstance.result.then(function (selectedItem) {
componentSchema.push(selectedItem);
}, function () {
// $log.info('Modal dismissed at: ' + new Date());
});
};
Here is the SourceCtrl that controls one of the modal dialogs I am using:
.controller("SourceCtrl", function ($scope, $modalInstance, existingSchemas) {
$scope.existingSchemas = existingSchemas;
$scope.sourceSchema = "";
$scope.ok = function () {
$modalInstance.close($scope.sourceSchema);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.$watch('sourceSchema', function(newValue, oldValue) {
console.log(newValue, oldValue);
})
})
And finally here is the template for this controller (SourceCtrl).
<div class="modal-header">
<h3>New Source Schema</h3>
</div>
<div class="modal-body">
<div class="row">
<div class="col-xs-3">
<label for="schema-source">Source</label>
</div>
<div class="col-xs-9">
<select name="sourceSchema" ng-model="sourceSchema" ng-options="s as s.name for s in existingSchemas">
<option value="">-- choose source --</option>
</select>
</div>
<h5>Name: {{sourceSchema.name}}</h5>
</div>
</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>
The funny thing is that when I change the value in the select, the {{sourceSchema.name}} line does show the correct name of the schema, however the changes do not get reflected in the controller and the actual value is not being passed on. I have used a watch to detect when something gets changed and apparently it doesn't. But the value does get changed otherwise why would it get displayed when I select it in the dropdown list.
Make sure that you've got a dot in your ngModel expression - that is - that you are binding to an object property and not directly to the scope. Something like:
.controller("SourceCtrl", function ($scope, $modalInstance, existingSchemas) {
$scope.existingSchemas = existingSchemas;
$scope.source = {
schema: ''
};
$scope.ok = function () {
$modalInstance.close($scope.source.schema);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.$watch('source.schema', function(newValue, oldValue) {
console.log(newValue, oldValue);
})
})
And then, in your markup:
<select name="sourceSchema" ng-model="source.schema" ng-options="s as s.name for s in existingSchemas">
<option value="">-- choose source --</option>
</select>
If you can provide a plunker I can help you fixing the code.

Resources