Can I use one Angular controller to change another? - javascript

I'm taking a pool of random animals, displaying two, then when I click the button of one animal, I want that one to stay and the other to be swapped out for a new one. Right now, I can change the animal that I want to stay in view, but can't figure out how to "reach across" and change the other controller's view.
I've tried setting ng-click="left.findNewAnimal()" on the right side but I get no response on click.
I've also looked at using a service or factory, but I'm not sharing data between controllers, I want to change the data of one, from the other. How can this be accomplished?
JavaScript:
angular.module("root", [])
.controller("leftAnimal", ["$scope",
function($scope) {
var self = this;
var animal
$scope.findNewAnimal = function() {
var randNum = Math.floor(Math.random() * animalPool.length);
animal = animalPool[randNum];
animalPool.splice(randNum, 1)
changeAnimal();
};
$scope.findNewAnimal();
function changeAnimal() {
$scope.name = animal.name;
$scope.img = animal.img;
}
}
])
.controller("rightAnimal", ["$scope",
function($scope) {
var self = this;
var animal
$scope.findNewAnimal = function() {
var randNum = Math.floor(Math.random() * animalPool.length);
animal = animalPool[randNum];
animalPool.splice(randNum, 1)
changeAnimal();
};
$scope.findNewAnimal();
function changeAnimal() {
$scope.name = animal.name;
$scope.img = animal.img;
}
}
])
.factory();
var Animal = function(data) {
this.name = data.name
this.img = data.img;
this.baby = data.baby;
};
var animals = [{
name: "Baby Quetzal",
img: "http://i.imgur.com/CtnEDpM.jpg",
baby: true
}, {
name: "Baby Otter",
img: "http://i.imgur.com/1IShHRT.jpg",
baby: true
}, {
name: "Baby Octopus",
img: "http://i.imgur.com/kzarlKW.jpg",
baby: true
}];
var animalPool = [];
var init = function() {
animals.forEach(function(animalData) {
animalPool.push(new Animal(animalData));
});
}
init();
<!doctype html>
<html ng-app="root">
<head>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
</head>
<body>
<div class="row">
<div class="text-center">
<h2>Pick an Animal</h2>
</div>
<div ng-controller="leftAnimal" class="col-md-6">
<div class="animalImage">
<img class="img-center" ng-src="{{img}}">
</div>
<div class="animalName">{{name}}</div>
<div class="animalDescription">{{description}}</div>
<button type="button" ng-click="findNewAnimal()" class="btn btn-info img-center">{{name}}</button>
</div>
<div ng-controller="rightAnimal" class="col-md-6">
<div class="animalImage">
<img class="img-center" ng-src="{{img}}">
</div>
<div class="animalName">{{name}}</div>
<div class="animalDescription">{{description}}</div>
<button type="button" ng-click="leftAnimal.findNewAnimal()" class="btn btn-info img-center">{{name}}</button>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="js/ang.js"></script>
</html>

If you only want simple event exchange between controllers you can use
$scope.$emit and $scope.$on :
//right
<button type="button" ng-click="emitEvent()" class="btn btn-info img-center">{{name}}</button>
//right controller
$scope.emitEvent = function(){
$scope.$emit('changeAnimal');
}
//left controller
$scope.$on('changeAnimal', function(event){
//do stuff
})
More on $scope events in official docs

As you stated, you can use Service to communicate to between controllers.
If you want to update other controller update automatically, you want to watch it.
http://plnkr.co/edit/iLnlZDyR1cZUQIiJJJEp
(function () {
angular.module("root", [])
.controller("leftAnimal", ["$scope", "animalService",
function ($scope, animalService) {
var source = false;
$scope.findNewAnimal = function () {
var randNum = Math.floor(Math.random() * animalPool.length);
console.log("Left Click Index: " + randNum);
animalService.setAnimal(randNum);
source = true;
};
$scope.$watch(function () {
return animalService.getAnimal();
}, function (value) {
if(!source) {
$scope.animal = animalPool[value];
}
source = false;
});
}
])
.controller("rightAnimal", ["$scope", "animalService",
function ($scope, animalService) {
var source = false;
$scope.findNewAnimal = function () {
var randNum = Math.floor(Math.random() * animalPool.length);
console.log("Right Click Index: " + randNum);
animalService.setAnimal(randNum);
source = true;
};
$scope.$watch(function () {
return animalService.getAnimal();
}, function (value) {
if(!source) {
$scope.animal = animalPool[value];
}
source = false;
});
}
])
.factory("animalService", [function () {
var index = 0;
function getAnimal() {
return index;
}
function setAnimal(newIndex) {
index = newIndex;
}
return {
getAnimal: getAnimal,
setAnimal: setAnimal,
}
}]);
var animalPool = [{
name: "Baby Quetzal",
img: "http://i.imgur.com/CtnEDpM.jpg",
baby: true
}, {
name: "Baby Otter",
img: "http://i.imgur.com/1IShHRT.jpg",
baby: true
}, {
name: "Baby Octopus",
img: "http://i.imgur.com/kzarlKW.jpg",
baby: true
}];
})();
<!DOCTYPE html>
<html ng-app="root">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div class="row">
<div class="text-center">
<h2>Pick an Animal</h2>
</div>
<div ng-controller="leftAnimal" class="col-md-6">
<div class="animalImage">
<img class="img-center" ng-src="{{animal.img}}"/>
</div>
<div class="animalName">{{animal.name}}</div>
<div class="animalDescription">{{animal.description}}</div>
<button type="button" ng-click="findNewAnimal()"
class="btn btn-info img-center">
Change
</button>
</div>
<div ng-controller="rightAnimal" class="col-md-6">
<div class="animalImage">
<img class="img-center" ng-src="{{animal.img}}" />
</div>
<div class="animalName">{{animal.name}}</div>
<div class="animalDescription">{{animal.description}}</div>
<button type="button" ng-click="findNewAnimal()"
class="btn btn-info img-center">
Change
</button>
</div>
</div>
</body>
</html>

Related

Angular Get Selected Value From Checkbox

I can't seem to get the selected item from an input checkbox.
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked(shoe.selected)'>Apply</button>
</ul>
Then in my controller:
$scope.whatIsChecked = function(selectedThing) {
console.log(selectedThing);
};
The above returns undefined.
The list items are displayed correctly, but the shoe.name or checked item doesn't seem to be stored by the ng-model.
the variable shoe is only valid in ng-repeat block.
If you want to got what is selected, you should try filter.
UPD:
Since you don't have the selected property, you should keep the selected items somewhere else by firing the ng-click event.
refer below code snippet.
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.checkedShoes = [];
$scope.shoebox = [{
name: 'shoe1'
},
{
name: 'shoe2'
},
{
name: 'shoe3'
},
{
name: 'shoe4'
}
];
$scope.save = function(e, shoe) {
if (e.target.checked) {
$scope.checkedShoes.push(shoe);
} else {
var index = $scope.checkedShoes.indexOf(shoe);
if( index > -1) {
$scope.checkedShoes.splice(index, 1);
}
}
};
$scope.whatIsChecked = function() {
//var selected = $scope.shoebox.filter(function(item) {
// return item.selected === true;
//});
console.log($scope.checkedShoes);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app" , ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-click="save($event, shoe)" id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked()'>Apply</button>
</ul>
</div>
You can get the checked items using a angular.Foreach it becomes easy when you have multiple items checked.
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.shoebox = [{
name: 'Reboke',
selected: false
}, {
name: 'woodlands',
selected: false
}, {
name: 'Nike',
selected: false
}, {
name: 'Fila',
selected: false
}];
$scope.checkedItems = function() {
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
}
});
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS </title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.7/angular.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='checkedItems()'>Apply</button>
Checked items are: {{checkedItems}}
</ul>
</body>
</html>

Angular ngModel doesn't fire Kendo change event

I have a Kendo model instance (person for this example) and watching it is modified or not by using dirty property.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Kendo + Angular</title>
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.common.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.default.min.css">
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.2.714/styles/kendo.mobile.all.min.css">
<script src="http://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.714/js/angular.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.714/js/jszip.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.714/js/kendo.all.min.js"></script>
</head>
<body>
<div ng-app="app" ng-controller="MainCtrl">
<div>Person name: {{ person.name }}</div>
<input type="text" name="name" ng-model="person.name"> <!-- This input don't work -->
<button ng-click="foo()">Foo</button> <!-- This button work because I call person.set method manually -->
<div>This person is modified? {{ person.dirty }}</div>
</div>
<script>
var Person = kendo.data.Model.define({
id: "personId", // the identifier of the model
fields: {
"name": {
type: "string"
},
"age": {
type: "number"
}
}
});
angular.module("app", ["kendo.directives"])
.controller("MainCtrl", function ($scope) {
$scope.person = new Person({
name: "John Doe",
age: 42
});
$scope.foo = function () {
$scope.person.set('name', "Kendo");
}
});
</script>
</body>
</html>
But when I type to text box dirty don't change because Angular ngModel doesn't fire Kendo "change" event. My real app have dozens of models like this, so is there any way to fix this automatically???
Thanks.
You can write a directive to replace for ng-model,
<input type="text" name="name" k-bind-model="person.name">
angular.module('app')
.directive("kBindModel", ["$parse", function ($parse) {
return {
restrict: "A",
scope: false,
link: function (scope, element, attributes, controller) {
var key = null;
var strs = attributes.kBindModel.split('.');
if (strs && strs.length > 1) {
key = strs[1];
}
var model = scope[strs[0]];
element.change(function () {
scope.$apply(function () {
model.set(key, element.val());
});
});
scope.$watch(attributes.kBindModel, function (n, o) {
element.val(n);
});
}
}
}]);

AngularJs, Img, onclick

I must do a website. On this website when you click on img it adds a text to the div.
It must has directives and controllers i dont have a clue how to do this...
<!DOCTYPE HTML>
<html>
<head>
<script src="http://code.angularjs.org/1.2.7/angular.min.js"></script>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="Stylesheet" type="text/css" href="styles/style.css">
<title>AngularJS System Zamówień</title>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope) {
$scope.data = new Date();
$scope.hambureger ={
nazwa: 'Hambureger',
cena: '5',
}
$scope.crips = {
nazwa: 'Crips',
cena: '4',
}
$scope.cola = {
nazwa: 'Coca-Cola',
cena: '3',
}
$scope.show = function() {
}
}
myApp.directive1('myDir1', function () {
return {
restrict: 'A',
template: '<br>{{hamburger.nazwa}}'
};
});
myApp.directive2('myDir2', function () {
return {
restrict: 'A',
template: '<br>{{frytki.nazwa}}
};
});
myApp.directive3('myDir3', function () {
return {
restrict: 'A',
template: '<br>{{cola.nazwa}}'
};
});
});
</script>
</head>
<body>
<h1 class="ladne"><center>System zamówień żarcia</center></h1>
<div class="d1" ng-app="myApp" ng-controller="myCtrl">
<img src="styles/img/cola.gif" ng-click=""></img>
<img src="styles/img/fryt.gif" ng-click=""></img>
<img src="styles/img/ham.gif" ng-click=""></img>
<br>
<div class="zam">
Data Zamówienia: {{data |date:'yyyy-MM-dd'}}
<br>
Twoje zamówienie: //HERE ANGULAR MUST ADD A TEXT
</div>
</div>
</body>
</html>
It's really hard for me to do this...
So let's explain one more time:
When u click on img, text is added to div(class="zam"), when you press next img it adds new text in new line. Here are 3 diffrent imgs Crips, Hambureger 'n' cola

How to add a todo from another Controller

I have a todo list in AngularJS that looks like this
.controller('TodoCtrl', function ($scope) {
$scope.todos = [
{text:'Ask smth on Stackoverflow', done:false},
{text: 'Resolve this', done:false}
];
$scope.getTotalTodos = function () {
return $scope.todos.length;
};
$scope.addTodo = function () {
$scope.todos.push({text:$scope.formTodoText, done:false});
$scope.formTodoText = '';
};
$scope.clearCompleted = function () {
$scope.todos = _.filter($scope.todos, function(todo){
return !todo.done;
});
};
})
And I would like to add a Todo (with a text, and a boolean 'done') from another controller that is launched when I click a button.
How can I do that ?
A big THANKS to who will help me
Typically services are used to pass information back and forth. Create a service and store your TODO list inside there. Inject that service into both controllers. Each controller can now act on the items in the list
I will append Scotts answer with some shorted Code.
Like he said, the best is to use a Service ;)
The Service:
.factory('todoService', function() {
var todolist = [];
return {
getTodoList: function() {
return todolist;
}
addTodo: function(todo) {
todolist.push(todo);
},
getTotalTodos: function() {
return todolist.length;
},
// some other
}
});
Now you can inject the service into any controller via
.controller('TodoCtrl', function ($scope, todoService)
and then you can call the functions of the service in the controller, e.g.
$scope.addTodo = function () {
todoService.addTodo({text:$scope.formTodoText, done:false});
$scope.formTodoText = '';
};
By using Angular Services:
I've made a simple demo.
Hope this helps.
(function() {
var app = angular.module("myApp", []);
// myService service.- This service contains an array, called «todos» wich contains data.
app.service("myService", function() {
return {
todos: [{
"text": "Ask smth on Stackoverflow",
"done": false
}, {
"text": "Resolve this",
"done": false
}]
};
});
// Add the dependecy in the controller.
app.controller("Controller", ["$scope", "myService",
function($scope, myService) {
$scope.title = "TODOS";
// This function returns the data stored in the service.
$scope.getTodos = function() {
return myService.todos;
}();
$scope.getTotalTodos = function() {
return myService.todos.length;
};
// This functions contains the object with the values from the form.
$scope.addTodo = function(model) {
myService.todos.push({
text: model.text,
done: model.done
});
$scope.model.text = "";
};
}
]);
})();
<html data-ng-app="myApp">
<head>
<meta charset="utf-8" />
<title>Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body data-ng-controller="Controller">
<h3>{{title}}</h3>
<form id="myForm" ng-submit="addTodo(model)">
<label>
Todo
<input type="text" data-ng-model="model.text" />
</label>
<br />
<label>
Done
<input type="checkbox" data-ng-model="model.done" />
</label>
<br/>
<button type="submit">Add</button>
<hr />
<ul>
<li data-ng-repeat="todo in getTodos">
{{todo.text}} ({{todo.done}})
<input type="checkbox" data-ng-model="todo.done" />
</li>
</ul>
</form>
</body>
</html>
Update: Using the service in multiple controllers.
(function() {
var example = angular.module("starter", [])
example.service("todoService", function() {
return {
todos: [],
addTodo: function($text, $classe) {
this.todos.push({
text: $text,
done: false,
});
}
};
});
example.controller('nationsLeaguesCtrl', function($scope, todoService) {
$scope.randomNationsLeagues = function() {
var text = "Text 1";
todoService.addTodo(text, null);
};
})
example.controller('statsCtrl', function($scope, todoService) {
$scope.randomStats = function() {
var text = "Text 2";
todoService.addTodo(text, null);
};
})
example.controller('specialCtrl', function($scope, todoService) {
$scope.randomSpecial = function() {
var text = "Text 3";
todoService.addTodo(text, null);
};
})
example.controller('TodoCtrl', function($scope, todoService) {
$scope.getTodos = function() {
return todoService.todos;
}();
$scope.getTotalTodos = function() {
return todoService.todos.length;
};
$scope.clearCompleted = function() {
$scope.todos = _.filter($scope.todos, function(todo) {
return !todo.done;
})
};
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="starter">
<button class="button button-full button-light" ng-controller="nationsLeaguesCtrl" ng-click="randomNationsLeagues()">Nations & Leagues</button>
<button class="button button-full button-light" ng-controller="statsCtrl" ng-click="randomStats()">Stats</button>
<button class="button button-full button-light" ng-controller="specialCtrl" ng-click="randomSpecial()">Special</button>
<div ng-controller="TodoCtrl">
<ul>
<li ng-repeat="todo in getTodos">{{todo.text}}
<input type="checkbox" name="checkboxG1" id="checkboxG1" ng-model="todo.done" class="css-checkbox" />
<label for="checkboxG1" class="css-label" style="font-family:checkboxFont; color:#ffffff;"><span class="done-{{todo.done}}"></span>
</label>
</li>
</ul>
</div>
</body>

ng-repeat working with array from JSON

I am having issues getting the ng-repeat to walkthrough my JSON response, I am new to AngularJS so I am sure its a newbie mistake :). I am trying to have the ng-repeat go through the ns0:AttributeDetails, ns0:Attributes. Here is the JSON data:
{"ns0:GetAgentProfile.Response": {
"xmlns:ns0": "http://URL",
"ns1:Header": {
"xmlns:ns1": "http://URL",
"xmlns:ns7": "http://URL",
"ns1:Source": null,
"ns1:CreatedDateTime": "2014-03-24T09:34:28.339-05:00",
"ns1:MessageType": "Request",
"ns1:MessageId": null
},
"ns0:ProfileDetails": {
"ns0:UserIdentifier": {
"ns0:UserGUID": "2BCF0074-392F-4653-8733-02063C2DBC5C",
"ns0:UserName": "Username01"
},
"ns0:AttributeDetails": {"ns0:Attribute": [
{
"ns0:Name": "AgentLogin",
"ns0:Value": ["Username01"]
},
{
"ns0:Name": "FullName",
"ns0:Value": ["Name, User"]
},
{
"ns0:Name": "LanguageSpoken",
"ns0:Value": ["English|Chinese"]
},
{"ns0:Name": "Supervisor"},
{
"ns0:Name": "Region",
"ns0:Value": ["Region01"]
},
{
"ns0:Name": "Country",
"ns0:Value": ["CO"]
},
{
"ns0:Name": "ClientAccessGroup",
"ns0:Value": ["CountryMobileCCR"]
},
{"ns0:Name": "Roles"}
]},
Here is the HTML:
<!DOCTYPE html>
<html ng-app="auth" xmlns="http://www.w3.org/1999/html">
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<script src="js/bootstrap.js"></script>
<script src="js/angular.js"></script>
<script src="js/authorization.js"></script>
</head>
<body ng-controller="MainCtrl">
<div>
<div class="container-fluid">
<form class="well">
<label>Username:</label>
<input><br><br>
<button ng-click="getData()" class="btn btn-primary">Submit</button>
<button ng-click="clearData()" class="btn btn-danger">Reset</button>
</form>
</div>
<h1>Response from Service:</h1>
<!-- <pre>{{data | json}}</pre> -->
<pre>
Username: {{data['ns0:GetAgentProfile.Response']['ns0:ProfileDetails'] ['ns0:UserIdentifier']['ns0:UserName']}} <br>
Profile Details</pre>
<div ng-repeat="Attribute in data">{{ data['ns0:GetAgentProfile.Response']['ns0:ProfileDetails']['ns0:AttributeDetails']['ns0:Attribute']['ns0:Name'] }}</div>
</div>
</html>
Here is the JS for the controller fetching the data:
var app = angular.module('auth', []);
app.factory('authService', function($http) {
var promise;
var authService = {
async: function() {
if ( !promise ) {
promise = $http.get('package.json').then(function (response) {
console.log(response);
return response.data;
});
}
return promise;
}
};
return authService;
});
app.controller('MainCtrl', function( authService,$scope) {
$scope.clearData = function() {
$scope.data = {};
};
$scope.getData = function() {
authService.async().then(function(d) {
$scope.data = d;
});
};
});
Again I apologize for the newbie question. Any assistance would be greatly appreciated.
Drill down to your array in the repeat directive:
<div ng-repeat="Attribute in data.ns0:GetAgentProfile.Response.ns0:ProfileDetails.ns0:AttributeDetails.ns0:Attribute">
And now you can do:
{{Attribute.ns0:Name}} and {{Attribute.ns0:Value}}
Not sure if the : will play nicely tho, may have to escape those.

Categories