I have checked all the other posts and trust me, this is not a duplicate. Hope someone can help me. Here is the code.
HTML Code- When user clicks on Report, buildData gets executed. multiselect directive name is mu-ls.
<button ng-click="buildData(selected_items)">Report</button>
<div>Universe:</div>
<div><mu-ls pre-selected="member.roles" model="selected_items" options="roles"></muls></div>
Directive Code- The directive name is muLs. User can select multiple options using this directive. The $scope.model gives the array of ids which user selected.
angular.module('Select').directive('muLs', function () {
return {
restrict: 'E',
scope: {
model: '=',
options: '=',
pre_selected: '=preSelected'
},
template: "<div data-ng-class='{open: open}'>" +
"<button data-ng-click='open=!open;openDropdown()'>Select...</button>" +
"<ul aria-labelledby='dropdownMenu'>" +
"<li data-ng-repeat='option in options'> <a data-ng-click='setSelectedItem()'>{{option.name}}<span data-ng-class='isChecked(option.id)'></span></a></li>" +
"</ul>" +
"</div>",
controller: function ($scope) {
$scope.openDropdown = function () {
$scope.selected_items = [];
for (var i = 0; i < $scope.pre_selected.length; i++) {
$scope.selected_items.push($scope.pre_selected[i].id);
}
};
$scope.setSelectedItem = function () {
var id = this.option.id;
if (_.contains($scope.model, id)) {
$scope.model = _.without($scope.model, id);
} else {
$scope.model.push(id);
}
console.log($scope.model);
return false;
};
$scope.isChecked = function (id) {
if (_.contains($scope.model, id)) {
return 'glyphicon glyphicon-ok pull-right';
}
return false;
};
}
}
});
Controller Code- This should show the list of selected items listed above in the controller side. It shows undefined at the moment.
'use strict'
var Modd= angular.module('Select', []);
Modd.controller('SelectController', function ($scope, $timeout, $rootScope) {
$scope.roles = [
{ "id": 1, "name": "USA" },
{ "id": 2, "name": "France" },
{ "id": 3, "name": "Russia" }
];
$scope.member = { roles: [] };
$scope.selected_items = [];
$scope.buildData = function (selected_items) {
console.log("This is", $scope.model);
}
});
QUESTION- How can i use this directive value $scope.model in the controller side ??? Please suggest guys !!!
I tried $scope.selected_items first. It gives a list of selected items only once. Once i click Report button, it will give the list. If i again start clicking and deselecting list items, it would still show the previous values. not the current ones.
$scope.model continues to show the latest values selected.
You are passing selected_items to your directive so it will contain the value of model in your controller.
$scope.buildData = function () {
console.log("This is", $scope.selected_items);
}
model is two-way bound. So if you assign a $scope variable from your controller to the module attribute, it will be updated when the selected value changes.
Therefore you can console.log($scope.selected_items);
Related
I neeed to pass a value from this part of the code in my directive to a controller, but not sure how to achieve that:
if (!scope.multiple) {
scope.model = value;
console.log(scope.model);
return;
}
I get the value in the console.log, I just don't know how to pass it to the controller.
This is the complete directive:
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;
console.log(scope.model);
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;
});
}
};
});
Updated
I tried to do as suggested in the answers by #Zidane and defining my object first in the controller like this:
$scope.year = {};
var saveUser = function(user) {
$scope.profilePromise = UserService.save(user);
console.log($scope.year);
This is the template:
<fancy-select
title="Klassetrinn"
model="year"
options="years"
enable="true"
on-change="onChangeYears()"
active="yearsActive"
name="playerYear"
form-name="registerForm"
>
</fancy-select>
But I got an empty object in that case.
When I define my objects like this I get the right value in the controller but in the view the title is not being displayed anymore:
$scope.search = {
years: []
};
var saveUser = function(user) {
$scope.profilePromise = UserService.save(user);
console.log($scope.search.years);
<fancy-select
title="Klassetrinn"
model="search.years"
options="years"
enable="true"
on-change="onChangeYears()"
active="yearsActive"
name="playerYear"
form-name="registerForm"
>
</fancy-select>
As you defined an isolated scope for your directive like this
scope: {
...
model: '=',
...
},
you give your directive a reference to an object on your controller scope.
Declaring the directive like <fancy-select model="myModel" ....></fancy-select> you pass your directive a reference to scope.myModel on your controller. When you modify a property on the scope.model object in your directive you automatically modify the same property on the scope.myModel object in your controller.
So you have to do
myApp.controller('myController', function($scope) {
...
$scope.myModel = {};
...
}
in your controller and in your directive just do
if (!scope.multiple) {
scope.model.value = value;
return;
}
Then you can get the value in your controller via $scope.myModel.value.
For clarification: You have to define an object on your controller and pass the directive the reference for this object so that the directive can follow the reference and doesn't mask it. If you did in your directive scope.model = 33 then you would just mask the reference passed to it from the controller, which means scope.model wouldn't point to the object on the controller anymore. When you do scope.model.value = 33 then you actually follow the object reference and modify the object on the controller scope.
you can use services or factories to share data between your angular application parts, for example
angular.module('myapp').factory('myDataSharing', myDataSharing);
function myDataSharing() {
var sharedData = {
fieldOne: ''
};
return {
setData: setData,
getData: getData,
};
function setData(dataFieldValue) {
sharedData.fieldOne = dataFieldValue;
};
function getData() {
sharedData.fieldOne
};
directive:
myDataSharing.setData(dataValue);
controller:
angular.module('myapp').controller('myController' ['myDataSharing'], function(myDataSharing) {
var myDataFromSharedService = myDataSharing.getData();
}
I'm trying to make a checkBox using AngularJS, I found this code :
http://jsfiddle.net/t7kr8/211/
and following its steps my code was :
JS File:
'use strict';
var app = angular.module('myApp.Carto', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/Carto', {
templateUrl: 'Carto/carto.html',
controller: 'CartoCtrl'
});
}])
app.controller('CartoCtrl', function($scope) {
$scope.array = [];
$scope.array_ = angular.copy($scope.array);
$scope.list = [{
"id": 1,
"value": "apple",
}, {
"id": 3,
"value": "orange",
}, {
"id": 5,
"value": "pear"
}];
});
app.directive("checkboxGroup", function() {
return {
restrict: "A",
link: function(scope, elem) {
// Determine initial checked boxes
if (scope.array.indexOf(scope.item.id) !== -1) {
elem[0].checked = true;
}
// Update array on click
elem.bind('click', function() {
var index = scope.array.indexOf(scope.item.id);
// Add if checked
if (elem[0].checked) {
if (index === -1) scope.array.push(scope.item.id);
}
// Remove if unchecked
else {
if (index !== -1) scope.array.splice(index, 1);
}
// Sort and update DOM display
scope.$apply(scope.array.sort(function(a, b) {
return a - b;
}));
});
}
};
});
However, when I run the code in the browser the checkbox appears but I can't chack the boxes, does that mean the directive doesn't work ?
I could'nt figure out what was going wrong because I practically just copied the code in the link provided above , can you please help me how to fix this ?
Thank you in advance
PS: I think it's due to materialize but I still don't know how or how to fix it
I think you've made a mistake with the module name.
I recreated your sample code and it works perfectly fine: JSFiddle
Code:
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.array = [];
$scope.array_ = angular.copy($scope.array);
$scope.list = [{
"id": 1,
"value": "apple",
}, {
"id": 3,
"value": "orange",
}, {
"id": 5,
"value": "pear"
}];
}
myApp.directive("checkboxGroup", function() {
return {
restrict: "A",
link: function(scope, elem) {
// Determine initial checked boxes
if (scope.array.indexOf(scope.item.id) !== -1) {
elem[0].checked = true;
}
// Update array on click
elem.bind('click', function() {
var index = scope.array.indexOf(scope.item.id);
// Add if checked
if (elem[0].checked) {
if (index === -1) scope.array.push(scope.item.id);
}
// Remove if unchecked
else {
if (index !== -1) scope.array.splice(index, 1);
}
// Sort and update DOM display
scope.$apply(scope.array.sort(function(a, b) {
return a - b
}));
});
}
}
});
HTML:
<div ng-controller="MyCtrl">
<div ng-repeat="item in list">
<input type="checkbox" checkbox-group />
<label>{{item.value}}</label>
</div>
</div>
The error was due to the presence of both bootstrap and Materialize , apparently there is a conflict between the two and when I deleted bootstrap, it all worked well
can you please tell me how to display the value of parameter on second view ?Actually I make a form in which there is two field : name and class .when user press(after filling fields) add it generate a row below .on click I get the value of name and class Now I want to show that name and value on next page .can we show this ?
http://plnkr.co/edit/NSZufLOX7bt52S3fdAXo?p=preview
app.controller("ctrl",['$scope',"$location",function(s,$location){
s.students = [];
s.add = function() {
s.students.push({
inputName : angular.copy(s.inputName),
inputclass : angular.copy(s.inputclass)
});
s.inputclass='';
s.inputName='';
}
s.getListClick=function(name,className){
alert(name+":"+className);
$location.path('/navigation')
}
}])
Thanks
As mentioned in the comments, you can do this using $routeParams, but if you want to share data between multiple controllers then a common way to do this is using a service that exposes getters and setters to each controller it is injected into.
app.factory('Data', function(){
var data =
{
name: '',
class: ''
};
return {
getName: function () {
return data.name;
},
setName: function (name) {
data.name = name;
},
getClass: function () {
return data.class;
},
setClass: function (klass) {
//class is reserved word :)
data.class = klass;
},
};
});
And then to share the data:
app.controller("ctrl",['$scope',"$location","Data",function(s,$location,Data){
s.students = [];
s.add = function() {
s.students.push({
inputName : angular.copy(s.inputName),
inputclass : angular.copy(s.inputclass)
});
Data.setName(s.inputName);
Data.setClass(s.inputclass);
s.inputclass='';
s.inputName='';
}
s.getListClick=function(name,className){
alert(name+":"+className);
$location.path('/navigation')
}
}]);
app.controller("secondCtrl",['$scope',"Data",function(s,Data){
s.name = Data.getName();
s.class = Data.getClass();
}]);
Then in each controller you can either check for updates to the data by using the getters, or use $watch to check for changes automatically:
s.$watch(function () { return Data.getName(); }, function (newVal) {
if (newValue) {
s.name = newVal;
}
});
Here's the plunkr: http://plnkr.co/edit/vm1wrahKYOLhvsKKyXj2?p=preview
EDIT:
Here's how to pass parameters between views using ngRoute and $routeParams (using the code you provided):
$routeProvider
.when('/home', {
templateUrl: 'tem.html',
controller: 'ctrl'
})
.when('/navigation/:name', {
templateUrl: 'second.html',
controller: 'secondCtrl'
})
.otherwise({
redirectTo: '/home'
});
And then in the controller you can use:
$location.path('/navigation/' + name);
And to read in the $routeParams:
app.controller("secondCtrl",['$scope',"$routeParams",function(s,routeParams){
s.name = routeParams.name;
}]);
http://plnkr.co/edit/kYwIEsBqSrJRJf37ZPI8?p=preview
I have a service which will make a call to the server and returns the data. I am binding service to a variable on scope.
Example:
Let the service be DataModelService
in the controller : $scope.data = DataModelService
in the view <div ng-repeat="value in data.persons">{{value.name}}</div>
My Code :
This is how my code looks like:
/**DataModelService**/
factory('DataModelService', [
'DataService',
function (DataService) {
var service;
service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
service.loadData(response.data);
});
},
loadData: function (responseData) {
service.persons = responseData.persons;
}
}
return service;
}
]);
/**DataService**/
factory('DataService', ['$http',
function ($http) {
return {
changePersonState: function (params) {
return $http.post("url", params);
}
}
}
]);
/**DataController**/
.controller('DataController', ['DataModelService',
function (DataModelService) {
$scope.data = DataModelService;
}
]);
/view/
<div ng-repeat = "person in data.persons" >{{person.name}} </div>
On the view I am doing a ng-repeat on a key in data i.e. ng-repeat="value in data.persons"
and also I have an option to change the state of person to active or inactive, so whenver i make a change to the state of the person, a call is sent to the server and data is set into the Service and as it is binded to the view, it should automatically update the data. But whats happening in my case, ng-repeat is not removing old data and instead it is appending new data to the old data.
For me its not good approach to write promise callback (then) into service. Because in your case, DataModelService returns data with some delay but not promise. And we don't know when.
So the way to make it work to add basic $timeout and fetch data from service by using other method.
So my suggestion is Demo
and your fixed example: Demo2
If we will take your example, it should be like:
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, DataModelService, $timeout) {
$scope.alertSwap = function () {
DataModelService.changeState('ff');
$timeout(function(){
$scope.data = DataModelService.getResponse();
}, 10);
}
});
fessmodule.$inject = ['$scope', 'Data', '$timeout'];
/**DataModelService**/
fessmodule.factory('DataModelService', [ 'DataService',function (DataService) {
var value = [];
var service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
value = response.persons;
});
},
getResponse : function(){
return value;
}
}
return service;
}
]);
/**DataService**/
fessmodule.factory('DataService', ['$q',function ($q) {
var data = { // dummy
persons: [{
name: "Bob"
}, {
name: "Mark"
}, {
name: "Kelly"
}]
};
var factory = {
changePersonState: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
} //function
]);
Currently, I am writing a test (using Jasmine) for a directive, and I suspect the link function is not being triggered.
The directive is as follows:
.directive('userWrapperUsername', [
'stringEntryGenerateTemplate',
'stringEntryGenerateLinkFn',
// UserWrapper username column
// Attribute: 'user-wrapper-username'
// Attribute argument: A UserWrapper object with a 'newData' key into an
// object, which contains a 'username' key holding the
// UserWrapper's username
function(stringEntryGenerateTemplate, stringEntryGenerateLinkFn) {
return {
template: stringEntryGenerateTemplate('username'),
restrict: 'A',
scope: true,
link: stringEntryGenerateLinkFn('userWrapperUsername', 'username')
};
}
])
So it makes use of 2 functions provided through factories, namely stringEntryGenerateTemplate and stringEntryGenerateLinkFn.
The stringEntryGenerateTemplate function takes in a string and returns a string.
The stringEntryGenerateLinkFn function, when called returns the actual link function. It mostly consists of event handlers so I shall simplify it to:
function stringEntryGenerateLinkFn(directiveName, key) {
return function(scope, element, attr) {
scope.state = {};
scope.userWrapper = scope.$eval(attr[directiveName]);
}
}
Here is how I use the directive:
<div user-wrapper-username="u"></div>
Here is my test case:
describe('UserWrapper Table string entry', function() {
var $scope
, $compile;
beforeEach(inject(function($rootScope, _$compile_) {
$scope = $rootScope.$new();
$compile = _$compile_;
}));
it('should be in stateDisplay if the value is non empty', function() {
var userWrapper = {
orgData: {
student: {
hasKey: true,
value: 'abcdef'
}
},
newData: {
student: {
hasKey: true,
value: 'abcdef',
changed: false
}
}
}
, key = 'student'
, elem
, elemScope;
$scope.userWrapper = userWrapper;
elem = $compile('<div user-wrapper-username="userWrapper"></div>')($scope);
elemScope = elem.scope();
expect(elemScope.userWrapper).toBe(userWrapper);
expect(elemScope.state).toEqual(jasmine.any(Object)); // this fails
});
});
So I get a test failure saying that elemScope.state is undefined. Recall that I had a scope.state = {}; statement and it should be executed if the link function is executed. I tried a console.log inside the link function and it is not executed as well.
So how do I trigger the link function?
Thanks!
It turns out that I have to initialize the module containing the factories stringEntryGenerateTemplate and stringEntryGenerateLinkFn, which is the same module that contains the userWrapperUsername directive by adding this into my test case:
beforeEach(module('userWrapper', function() {}));
where userWrapper is the name of the module.
So the test case becomes:
describe('UserWrapper Table string entry', function() {
var $scope
, $compile;
beforeEach(module('userWrapper', function() {}));
beforeEach(inject(function($rootScope, _$compile_) {
$scope = $rootScope.$new();
$compile = _$compile_;
}));
it('should be in stateDisplay if the value is non empty', function() {
var userWrapper = {
orgData: {
student: {
hasKey: true,
value: 'abcdef'
}
},
newData: {
student: {
hasKey: true,
value: 'abcdef',
changed: false
}
}
}
, key = 'student'
, elem
, elemScope;
$scope.userWrapper = userWrapper;
elem = $compile('<div user-wrapper-username="userWrapper"></div>')($scope);
elemScope = elem.scope();
expect(elemScope.userWrapper).toBe(userWrapper);
expect(elemScope.state).toEqual(jasmine.any(Object)); // this fails
});
});
This seems like quite a big oversight on my part. Hopefully this will help anyone facing a similar issue.