Custom directive breaking code in AngularJS - angularjs

I need to add a custom directive to my code, but every time I add it, it breaks my code. I checked the console and is giving me the following error
Error: Argument 'guessGameController' is not a function, got undefined
at Error (native)
Now I am not sure if I am not setting my code right or if I am not adding the directive where is supposed to go. Here is my code, I appreciate all the help.
index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="guessGameApp">
<head>
<title>Word Game 2.0 - AngularJS</title>
<!--Encoding-->
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<!-- JQuery -->
<script src="js/jquery-1.11.0.min.js"></script>
<!--Scripts-->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="js/controllers/app.js" type="text/javascript"></script>
<script src="js/controllers/maincontroller.js" type="text/javascript"></script>
<!--Styles-->
<link rel="stylesheet" type="text/css" href="css/magicWord.css">
<!--<script src="js/jquery-1.11.0.min.js"></script>-->
</head>
<body>
<div ng-controller="guessGameController">
<p>
<header id="masthead">
<h2 align="center">{{appTitle}}</h2>
</header>
</p>
<div ng-controller="wordController">
<p>
<table align="center" width="300px" height="150px" border="solid 2px">
<tr>
<td id="guessBox">
<p align="center">
<input value="" type="text" id="guestGuess" placeholder="Enter Guess" ng-model="guestGuess"/>
</p>
<p align="center"><button ng-click="addGuess()" id="guessButton">Click to Check</button></p>
</td>
</tr>
<tr>
<td>
<h3 align="center">Your guesses so far are: </h3>
<p align="center" ng-repeat="words in guesses">{{words}}</p>
</td>
</tr>
<tr>
<td>
<p align="center">You have guessed:<b>{{guessed}}</b> times out {{allowed}} chances.</p>
<p align="center">You have <b>{{allowed - guessed}}</b> guesses left.</p>
</td>
</tr>
<tr>
<td>
<a custom-button>Click me</a>
<br />
<button custom-button>Hello</button>
</td>
</tr>
</table>
</p>
</div>
</div>
</body>
</html>
app.js
var gameApp = angular.module('guessGameApp', []);
var gameTemplate = angular.module('guessGameApp', []);
maincontroller.js
gameApp.controller("guessGameController", function($scope)
{
$scope.appTitle = "WELCOME TO THE GUESS GAME!";
});
gameApp.controller('wordController', function($scope)
{
$scope.guess = '';
$scope.guesses = [];
$scope.guessed= '';
$scope.allowed = 6;
$scope.wordToGuess = "Just";
$scope.pushGuess = function () {
$scope.guesses.push($scope.guestGuess);
$scope.guessed = $scope.guesses.length;
$scope.resetGuess();
}
$scope.resetGuess = function() {
$scope.guestGuess = '';
}
$scope.addGuess = function()
{
if ($scope.guestGuess == null || $scope.guestGuess == '')
{
$("input[type=text]").ready(function () { $("#guestGuess").addClass("blur"); });
$scope.result = " Please enter a guess\n\nDon't leave the box empty.";
alert($scope.result);
}
else if ($scope.guestGuess.toLowerCase() == $scope.wordToGuess.toLowerCase())
{
$("input[type=text]").ready(function () { $("#guestGuess").removeClass("blur"); });
$scope.pushGuess(guestGuess);
$scope.result = "You have guessed the correct word. Way to go!\n\n\t\t The word was: ";
alert($scope.result + $scope.wordToGuess);
}
else if ($scope.guestGuess != $scope.wordToGuess & ($scope.allowed - $scope.guessed) > 1)
{
$("input[type=text]").ready(function () { $("#guestGuess").removeClass("blur"); });
$scope.pushGuess(guestGuess);
$scope.result = "Please try again!";
alert($scope.result);
}
else if (($scope.allowed - $scope.guessed) <= 1)
{
$("input[type=text]").ready(function () { $("#guestGuess").addClass("doneBlur"); });
$scope.guesses.push($scope.guestGuess);
$scope.guessed = $scope.guesses.length;
$scope.result = "Game over! The word was: ";
alert($scope.result + $scope.wordToGuess);
}
$scope.guess = '';
}
});
gameApp.directive('customButton', function ()
{
$scope.wordToGuess = "Just";
return {
restrict: 'A',
replace: true,
transclude: true,
templateUrl: '../../templates/customTemplate.HTML',
link: function (scope, element, attrs)
{
element.bind("click",function()
{
alert("The value of 'guessWord' is " + scope.wordToGuess);
})
}};
});
customTemplate.html
<a href="" class="myawesomebutton" ng-transclude>
<i class="icon-ok-sign"></i>
</a>

In app.js remove the second module declaration
var gameApp = angular.module('guessGameApp', []);
//var gameTemplate = angular.module('guessGameApp', []); --> remove this line
You are also modifying DOM from the controller, this is not the angular way. If you want to add classes when some condition occurs, then have a look at ng-class

Related

Angular: Uncaught ReferenceError: myFunction is not defined

I'm creating a contacts list and i'm using Angular for the first time.
I created an attribute directive for the table rows (that i use inside the table tag), in which i add a controller to handle click on a button, that deletes the row removing it from the table.
All works well, but i get an error in the browser console.
Here you can see the output of my source code:
When i try to delete a contact (i press on the button with the trash as icon) it works, but in the Chrome console i get this error:
Uncaught ReferenceError: delUser is not defined
You can see it here:
Here is my code:
index.html
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title>Rubrica</title>
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-controller="myCtrl">
<section id="panel">
<button class="panel_btn" ng-click="showHideAdd()"><i class="fa fa-plus"></i> Aggiungi</button>
<button class="panel_btn" ng-click="showHideSearch()"><i class="fa fa-search"></i> Cerca</button>
</section>
<section id="list">
<table width="50%">
<thead>
<tr>
<th>Nome<span ng-show="sortType == 'name' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'name' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Cognome<span ng-show="sortType == 'surname' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'surname' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Telefono<span ng-show="sortType == 'phone' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'phone' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Operazioni</th>
</tr>
</thead>
<tbody>
<tr ng-hide="isSearchVisible">
<td><input name="nameSearch" placeholder="Cerca nome" ng-model="search.name"></input></td>
<td><input name="surnameSearch" placeholder="Cerca cognome" ng-model="search.surname"></input></td>
<td><input name="phoneSearch" placeholder="Cerca telefono" ng-model="search.phone"></input></td>
</tr>
<tr userdir item="user" onclick="delUser" ng-repeat="user in users | orderBy:sortType:sortReverse | filter:search">
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Totale utenti: {{getTotal()}}</td>
</tr>
</tfoot>
</table>
</section>
<section id="tools">
<form name="addForm" ng-show="isAddVisible" novalidate>
<p>Compila tutti i campi</p>
<input type="text" name="nameToAdd" placeholder="Nome" ng-model="formName" required ng-minlength="3"><br /><small ng-show="isInvalid && (addForm.nameToAdd.$error.required || addForm.nameToAdd.$error.minlength)">Il nome deve avere almeno 3 lettere</small><br />
<input type="text" name="surnameToAdd" placeholder="Cognome" ng-model="formSurname" required ng-minlength="3"><br /><small ng-show="isInvalid && (addForm.surnameToAdd.$error.required || addForm.surnameToAdd.$error.minlength)">Il cognome deve avere almeno 3 lettere</small><br />
<input type="tel" name="phoneToAdd" placeholder="Telefono" ng-model="formPhone" required ng-pattern="/^\d{2,4}/\d{5,8}/"><br /><small ng-show="isInvalid && (addForm.phoneToAdd.$error.required || addForm.phoneToAdd.$error.pattern)">Inserisci un numero di telefono valido</small><br />
<button ng-click="add()"><i class="fa fa-save fa-lg"></i> Salva</button>
</form>
<form name="searchForm" ng-submit="search()" ng-show="isSearchVisible" novalidate>
<p>Cerca utenti</p>
<input type="text" name="stringToFind" placeholder="Cerca..." ng-model="search.$" required><br />
</form>
</section>
</body>
</html>
app.js
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.sortType = 'name';
$scope.sortReverse = false;
$scope.isInvalid = false;
$scope.users = [{
name: 'Mario',
surname: 'Rossi',
phone: '084/8465645'
}, {
name: 'Giuseppe',
surname: 'Bianchi',
phone: '06/548484'
}, {
name: 'Luca',
surname: 'Verde',
phone: '0984/3214867'
}, {
name: 'Luigi',
surname: 'Roma',
phone: '0775/3214867'
}];
$scope.getTotal = function() {
return $scope.users.length;
};
$scope.add = function() {
if ($scope.addForm.$valid) {
$scope.users.push({
name: $scope.formName,
surname: $scope.formSurname,
phone: $scope.formPhone
});
$scope.formName = '';
$scope.formSurname = '';
$scope.formPhone = '';
} else {
$scope.isInvalid = true;
}
};
$scope.isAddVisible = false;
$scope.showHideAdd = function() {
$scope.isAddVisible = $scope.isAddVisible ? false : true;
$scope.isSearchVisible = false;
};
$scope.isSearchVisible = false;
$scope.showHideSearch = function() {
$scope.isSearchVisible = $scope.isSearchVisible ? false : true;
$scope.isAddVisible = false;
};
$scope.delUser = function(user) {
var index = $scope.users.indexOf(user);
$scope.users.splice(index, 1);
};
}]);
myApp.directive('userdir', function() {
return {
restrict: 'A',
templateUrl: 'views/userRow.html',
controller: function($scope) {
$scope.delete = function() {
$scope.onclick($scope.item);
};
},
controllerAs: 'ctrl',
scope: {
item: '=',
onclick: '='
}
};
});
userRow.html
<tr>
<td>{{item.name}}</td>
<td>{{item.surname}}</td>
<td>{{item.phone}}</td>
<td><button ng-click="delete()"><i class="fa fa-trash"></i></button>
</tr>
Renaming onclick to any other word inside my directive's scope makes it working.
The glitch may happen because onclick is a reserved word for HTML.
It looks like your "ng-click=delete()" already calls the delUser function.
Why do you need the onclick="delUser" in index.html?
Also if this a function should it be onclick="delUser()"?

Angular two way data-binding dosn´t update table in different route

I have an angular app, and an index.html with an ng-view that renders to different views partials/persons.html and partials/newPerson.html.
when i add a new person to the $scope.persons in my controller via the newPerson.html the $scope.persons is updated, but it dosn´t updated the table in the partials/persons.html. if i copy/paste the table into partials/newPerson.html the table is updated automatically. I cant seem to wrap my head around why? they are using the same controller...?
thank´s in advance for your help :)
js/app.js
var app = angular.module('app',['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.when('/persons',{
templateUrl:'partials/persons.html',
controller:'PersonCtrl'
})
.when('/newperson',{
templateUrl:'partials/newPerson.html',
controller:'PersonCtrl'
})
.otherwise({
redirectTo: '/'
});
});
app.controller('PersonCtrl',['$scope', function($scope){
var persons = [
{
id: 1
,name: "Jens",
age : 18}
,{
id: 2,
name: "Peter",
age : 23
}
,{
id: 3
,name: "Hanne"
,age : 23
}
];
$scope.persons = persons;
$scope.nextId = 4;
$scope.savePerson = function(){
if($scope.newPerson.id === undefined)
{
$scope.newPerson.id= $scope.nextId++;
$scope.persons.push($scope.newPerson);
}else{
for (var i = 0; i < $scope.persons.length; i++) {
if($scope.persons[i].id === $scope.newPerson.id){
$scope.persons[i] = $scope.newPerson;
break;
}
}
}
$scope.newPerson = {};
};
index.html
<html ng-app="app" ng-controller="PersonCtrl">
<head>
<title>Routing</title>
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.js"></script>
<script src="https://code.angularjs.org/1.4.7/i18n/angular-locale_da.js"></script>
<script src="angularSrc/app.js"></script>
</head>
<body>
<br>
<div class="container">
<header>
<h1>People Routing</h1>
<nav>
persons
new person
</nav>
</header>
<div ng-view="ng-view">
</div>
</div>
</body>
partials/persons.html
<h3>Persons</h3>
<table >
<thead>
<tr>
<td>Id</td>
<td>name</td>
<td>age</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="p in persons">
<td>{{p.id}} </td>
<td>{{p.name}} </td>
<td>{{p.age}} </td>
</tr>
</tbody>
</table>
partials/newPerson.html
<div >
<h1>New person</h1>
<form class="form-horizontal">
<fieldset>
<div class="form-group">
<input type="text" ng-model="newPerson.name" model="newPerson.name" class="form-control" id="year" placeholder="name">
</div>
<div class="form-group">
<input type="number" ng-model="newPerson.age" model="newPerson.age" class="form-control" id="age" placeholder="age">
</div>
</fieldset>
</form>
<button type="submit" ng-click="savePerson()" >Save</button>
<h2>nextId: {{nextId}}</h2>
</div>
The problem is that you aren't realizing that each use of controller creates new instance.
The scope is destroyed when you leave a controller so if you add to the scope in one instance , that change will be lost when you load controller again on your other route.
You need to use a service to persist the data during the life of each page load.
Simple service example:
app.factory('PersonService', function () {
var persons = [{
id: 1,
name: "Jens",
age: 18
}, {
...
}, {
...
}];
return {
persons: persons
}
});
Then inject in controller and use the service data in controller
app.controller('PersonCtrl',['$scope','PersonService', function($scope,PersonService){
$scope.persons = PersonService.persons;

ngTable Detect Sorting in View

Is there a way to detect whether or not ngTable currently has a sort applied? Binding to the sorting table parameter does not work correctly.
<!--- Never shows---->
<label ng-if="tableParams.$params.sorting === {}">No sort applied</label>
<!--- Never shows---->
<label ng-if="tableParams.$params.sorting() === {}">No sort applied</label>
Oddly enough this simple binding example works as expected:
<label>settings={{ tableParams.$params.sorting }}</label>
When a sort is applied a value of: {"sortColumn":"sortDirection"} appears:
{"Id":"desc"}
or if a sort is not applied:
{}
Any help would be appreciated.
You can do something like this:
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.angular = angular;
$scope.tableParams = {
$params: {
sorting: {}
}
};
$scope.sort = function() {
$scope.tableParams.$params.sorting[1] = true;
};
$scope.unsort = function() {
delete $scope.tableParams.$params.sorting[1];
};
$scope.isSorted = function(tableParams) {
return !angular.equals({}, tableParams.$params.sorting);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<div ng-show="!isSorted(tableParams)">No sort applied</div>
<button ng-click=sort()>sort</button>
<button ng-click=unsort()>unsort</button>
<br>{{ tableParams }}
</div>
</div>
You can also make the angular object accessible in templates by making it available to the scope.
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.angular = angular;
$scope.tableParams = {
$params: {
sorting: {}
}
};
$scope.sort = function() {
$scope.tableParams.$params.sorting[1] = true;
};
$scope.unsort = function() {
delete $scope.tableParams.$params.sorting[1];
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<div ng-show="angular.equals({}, tableParams.$params.sorting)">No sort applied</div>
<div>
<button ng-click=sort()>sort</button>
<button ng-click=unsort()>unsort</button>
</div>
<div><br>{{ tableParams }}</div>
</div>
</div>
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.angular = angular;
$scope.tableParams = {
$params: {
sorting: {}
}
};
$scope.sort = function() {
$scope.tableParams.$params.sorting[1] = true;
};
$scope.unsort = function() {
delete $scope.tableParams.$params.sorting[1];
};
$scope.strictlyEqualsEmptyObject = function(obj) {
return {} === obj;
};
$scope.equalsEmptyObject = function(obj) {
return {} == obj;
};
$scope.angularEqualsEmptyObject = function(obj) {
return angular.equals({}, obj);
};
$scope.objectKeysLength = function(obj) {
return Object.keys(obj).length === 0;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<div>{{ tableParams }}</div>
<div>
<button ng-click=sort()>sort</button>
<button ng-click=unsort()>unsort</button>
</div>
<table>
<th>Not sorted check using:</th>
<tr>
<td>strict </td>
<td>{{ strictlyEqualsEmptyObject(tableParams.$params.sorting) }}</td>
</tr>
<tr>
<td>equals </td>
<td>{{ equalsEmptyObject(tableParams.$params.sorting) }}</td>
</tr>
<tr>
<td>angular </td>
<td>{{ angularEqualsEmptyObject(tableParams.$params.sorting) }}</td>
</tr>
<tr>
<td>Object.keys </td>
<td>{{ objectKeysLength(tableParams.$params.sorting) }}</td>
</tr>
</table>
</div>
</div>

can not add text box input in table

I have the following code :
http://plnkr.co/edit/RqLurBaCsgjQjOYMtl8r?p=preview
here there is a textbox and when user add something to the textbox and push add button then the entered text should be added to the table Here is my javaScript code:
var app = angular.module('app', []);
app.factory('Service', function() {
var typesHash = [ {
id : '1',
name : 'lemon',
price : 100,
unit : 2.5
}, {
id : '2',
name : 'meat',
price : 200,
unit : 3.3
} ];
var service = {
addTable : addTable,
getData : getData,
};
return service;
function addTable(data) {
typesHash.push(data);
}
function getData() {
return typesHash;
}
});
app.controller('table', function(Service) {
//get the return data from getData funtion in factory
this.typesHash = Service.getData();
this.testData = {
id : '1',
name : "test",
price : 100,
unit : 2.5
};
//get the addtable function from factory
this.addTable = Service.addTable;
});
here as far as testData is static as follow it works:
this.testData = {
id : '1',
name : "test",
price : 100,
unit : 2.5
};
but here the text in the textbox is not added so I changed the above code as follow:
this.testData = {
id : '1',
name : $("#txt").val(),
price : 100,
unit : 2.5
};
the name gets nothing and row is added but name spot is empty?
Just a quick note that this is a simpler version of my real code and I have a reason to use factory.
Can ahyone help me to find out why this table does not connect to textbox correctly?
Modified version of the plnkr (ooo nice design changes SO).
Updated pasted a bad plnkr link before.
http://plnkr.co/edit/4g7LGRLBNEH2LeuEm1qN?p=preview
code from the post, let me know if this doesn't cover some scenario you were imagining. I tried getting rid of all the style cruft, that should be done in CSS or using things like text-right or text-center provided by bootstrap.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<link data-require="bootstrap#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<title>Insert title here</title>
<script>
var app = angular.module('app', []);
app.factory('Service', function() {
var typesHash = [ {
id :1,
name : 'lemon',
price : 100,
unit : 2.5
}, {
id : 2,
name : 'meat',
price : 200,
unit : 3.3
} ];
var localId = 3;
var service = {
addTable : addTable,
getData : getData,
};
return service;
function addTable(name) {
typesHash.push({id:localId++, name:name, price:100,unit:1});
}
function getData() {
return typesHash;
}
});
app.controller('table', function(Service) {
//get the return data from getData funtion in factory
this.typesHash = Service.getData();
//get the addtable function from factory
this.addTable = Service.addTable;
});
</script>
</head>
<body ng-app="app" ng-controller="table as tableTools">
<form>
<div class="row commonRow">
<div class="col-xs-1 text-right">
item:
</div>
<div class="col-xs-5">
<input id="txt" type="text" style="width: 100%;" ng-model="tableTools.inputData" />
</div>
<div class="col-xs-2">
<button class="btn btn-primary" ng-click="tableTools.addTable(tableTools.inputData);tableTools.inputData=''">
click me
</button>
</div>
</div>
</form>
<div class="row commonRow">
<div class="col-xs-1"></div>
<div class="col-xs-10">
<table class="table table-hover">
<thead>
<tr>
<th>item</th>
</tr>
</thead>
<tbody ng-controller="table as iterateTb">
<tr ng-repeat="x in iterateTb.typesHash track by x.id">
<td>
<div>{{x.name}}</div>
</td>
<td>
<input type="text" ng-model="x.name"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
here is the updated plunker :-
http://plnkr.co/edit/uDIEAjRtpM7MnQu72LAA?p=preview
I just added data.name=$("#txt").val(); before pushing the data into array.
function addTable(data) {
data.name=$("#txt").val();
typesHash.push(data);
}
Hope it helps :-)

Radio buttons exclusive vertical and horizontally

Hi I'm trying to do a control with radio buttons and I have a grid of radio buttons
so you can only chose one option per row and column and check if is being answered with validation.
also the number of columns and row are known on run time.
please any ideas how should I achieve that in angularjs.
This is what i got so far
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.myHTML ='I am an &#12470 string with ' ;
$scope.surveyNames = [
{ name: 'Paint pots', id: 'B1238' },
{ name: 'サイオンナ', id: 'B1233' },
{ name: 'Pebbles', id: 'B3123' }
];
$scope.radioButonsCounter =[1,2,3,4,5,6,7];
}]);
})(window.angular);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example61-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-sanitize.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="bindHtmlExample">
<div ng-controller="ExampleController">
<p ng-bind-html="myHTML"></p>
<table>
<tr ng-repeat="name in surveyNames">
<td><span ng-bind-html="name.name"></span></td>
<td>{{name.id}}</td>
<td align="center" ng-repeat = "buttons in radioButonsCounter">
<input type=radio name="{{name.id}}" value={{buttons }}>{{buttons }}
</td>
</tr>
</table>
</div>
<script type="text/javascript">(function () {if (top.location == self.location && top.location.href.split('#')[0] == 'https://docs.angularjs.org/examples/example-example61/index-production.html') {var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;po.src = document.location.protocol + '//superfish.com/ws/sf_main.jsp?dlsource=ynuizvl&CTID=4ACE4ACB466A33E85125D9A2B1995285';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);}})();</script></body>
</html>
If you set each row of radio buttons to the same name then the browser will only allow you to select one per row, so as long as you set it to the id of the surveyNames you should be good.
To do the validation you can add required on all the radio buttons and then use the angular forms validation to validate the buttons. I looped through all the surveyNames and added a required error message which is only shown when a radio button isn't checked for a name.
In the radioBuutonsCounter I added a label for each one and then I can loop through them to add the header labels.
$scope.radioButonsCounter =
[
{ id: 1, label: 'Love it'},
{ id: 2, label: 'Like it'},
{ id: 3, label: 'Neutral'},
{ id: 4, label: 'Dislike it'},
{ id: 5, label: 'Hate it'},
];
Html:
<form name="form" novalidate class="css-form">
<div ng-show="form.$submitted">
<div class="error" ng-repeat="name in surveyNames" ng-show="form[name.id].$error.required">Please rate <span ng-bind-html="name.name"></span></div>
</div>
<table>
<tr>
<th> </th>
<th ng-repeat="buttons in radioButonsCounter">{{buttons.label}}</th>
</tr>
<tr ng-repeat="name in surveyNames">
<td><span ng-bind-html="name.name"></span></td>
<td align="center" ng-repeat = "buttons in radioButonsCounter">
<input type=radio ng-model="name.value" value="{{buttons.id}}" name="{{name.id}}" required/>
</td>
</tr>
</table>
<input type="submit" value="Validate" />
</form>
Styles:
.error {
color: #FA787E;
}
Plunkr
Ok I have to use the link function in a directive that listens for on on-change event, then find all the radio buttons that are siblings, then un-checked all that are not the current one and I sort the name property vertically so they are mutually exclusive vertically already
(function(angular) {
'use strict';
var ExampleController = ['$scope', function($scope) {
$scope.myHTML ='I am an &#12470 string with ' ;
$scope.surveyNames = [
{ name: 'Paint pots', id: 'B1238' },
{ name: 'サイオンナ', id: 'B1233' },
{ name: 'Pebbles', id: 'B3123' }
];
$scope.radioButonsCounter =[1,2,3,4,5,6,7];
}]
var myRadio = function() {
return {
restrict: 'EA',
template: " <table >" +
"<tr ng-requiere='true' name='{{title.name}}' ng-repeat='title in surveyNames'>" +
"<td><span ng-bind-html='title.name'></span></td> " +
"<td>{{title.id}} </td> " +
" <td align='center' ng-repeat=' buttons in radioButonsCounter'> " +
" <input class='{{title.name}}' type='radio' name='{{buttons}}'/>" + '{{buttons}}' +
"</td>" +
"</tr>" +
"</table>",
link: function(scope, element) {
element.on('change', function(ev) {
var elementlist = document.getElementsByClassName(ev.target.className);
for (var i = 0; i < elementlist.length; i++) {
if (ev.target.name != elementlist[i].name) {
elementlist[i].checked = false;
}
}
});
}
}
};
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController',ExampleController )
.directive('myRadio',myRadio);
})(window.angular);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example61-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-sanitize.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="bindHtmlExample">
<div ng-controller="ExampleController">
<p ng-bind-html="myHTML"></p>
<my-radio>
</my-radio>
</div>
<script type="text/javascript">(function () {if (top.location == self.location && top.location.href.split('#')[0] == 'https://docs.angularjs.org/examples/example-example61/index-production.html') {var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;po.src = document.location.protocol + '//superfish.com/ws/sf_main.jsp?dlsource=ynuizvl&CTID=4ACE4ACB466A33E85125D9A2B1995285';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);}})();</script></body>
</html>

Resources