Creating dynamic multiple tables using Angular - javascript

I have created a dynamic table that allows the user to add rows to the table. Now I want to create multiple tables that allow the user to add multiple rows.
The problem with my code is that the 'variable' choice is shared and making any changes to any of the fields in any of the tables causes all the table fields to replicate the behaviour. Can someone tell me how to create tables that are capable of holding different values?
Angular.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="createQuiz.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.min.js">
</script>
<script src="quizMgmt.js"></script>
</head>
<body>
<div ng-app="angularjs-starter" ng-controller="MainCtrl">
<form action="/createQuiz">
<ul class="list-group" data-ng-repeat="path in path">
<span>
<h1 ng-model="colNum" >Path {{colNum}}</h1>
<button class="btn btn-primary" ng-click="addNewPath()">Add New Path</button>
</span>
<li class="list-group-item" data-ng-repeat="choice in choices">
<span>
<span class="col-sm-2">
<select class="form-control" ng-model="choice.type" name="item" ng-options="item for item in selectOptions">
</select>
</span><br>
<span class="col-sm-9">
<input class="form-control" type="text" ng-model="choice.name" name="value" placeholder="Enter mobile number">
</span>
<button class="btn btn-danger" ng-click="removeChoice(choice.id)" ng-if="choice.id!=index">-</button>
<button class="btn btn-danger" ng-click="addNewChoice()" ng-if="choice.id===index">+</button>
</span>
</li>
</ul>
<br>
<button class="btn btn-primary" ng-click="addNewChoice()">Add fields</button>
<input type="submit">
</form>
<br>
<br>
<div id="choicesDisplay">
<!-- {{ choices }} -->
{{path}}
</div>
</div>
</body>
quizMgmt.js
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.selectOptions = ["Mobile",
"Office",
"Home"
];
$scope.choices = [{"id": 1,"type":"Mobile","name":""},
{"id": 2,"type":"Mobile","name":""}];
$scope.path =[{"NumPath":1, 'path':$scope.choices}];
$scope.colNum=1;
$scope.index = $scope.choices.length;
$scope.addNewChoice = function() {
var newItemNo = ++$scope.index;
$scope.choices.push({'id':newItemNo, "type":"Mobile","name":""});
};
$scope.addNewPath= function() {
var NumPath=$scope.path.length;
console.log($scope.path.length)
$scope.colNum=NumPath;
$scope.path.push({"NumPath": NumPath,'path':$scope.choices});
};
$scope.removeChoice = function(id) {
if($scope.choices.length<=1){
alert("input cannot be less than 1");
return;
}
var index = -1;
var comArr = eval( $scope.choices );
for( var i = 0; i < comArr.length; i++ ) {
if( comArr[i].id === id) {
index = i;
break;
}
}
if( index === -1 ) {
alert( "Something gone wrong" );
}
$scope.choices.splice( index, 1 );
};
});

Issue is with the $scope.choices which is common object , So it is getting replicated.
$scope.choices must be isolated and restrict it to that respective path like below.
I believe by default you need to two choices while adding new path. Hope this helps.
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.selectOptions = ["Mobile",
"Office",
"Home"
];
$scope.getDefaultChoices = function() {
return [{"id": 1,"type":"Mobile","name":""},
{"id": 2,"type":"Mobile","name":""}];
};
$scope.choices = $scope.getDefaultChoices();
$scope.paths = [{"NumPath":1, 'choices':$scope.choices}];
$scope.colNum=1;
$scope.index = $scope.choices.length;
$scope.addNewChoice = function(path) {
var newItemNo = ++$scope.index;
path.choices.push({'id':newItemNo, "type":"Mobile","name":""});
};
$scope.addNewPath= function() {
var NumPath=$scope.paths.length;
console.log($scope.paths.length)
$scope.colNum=NumPath;
$scope.paths.push({"NumPath": NumPath,'choices': $scope.getDefaultChoices() });
};
$scope.removeChoice = function(path, id) {
if(path.choices.length<=1){
alert("input cannot be less than 1");
return;
}
var index = -1;
var comArr = eval( path.choices );
for( var i = 0; i < comArr.length; i++ ) {
if( comArr[i].id === id) {
index = i;
break;
}
}
if( index === -1 ) {
alert( "Something gone wrong" );
}
path.choices.splice( index, 1 );
};
});
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.min.js">
</script>
</head>
<body>
<div ng-app="angularjs-starter" ng-controller="MainCtrl">
<form>
<ul class="list-group" data-ng-repeat="path in paths">
<span>
<h1 ng-model="colNum" >Path {{colNum}}</h1>
<button class="btn btn-primary" ng-click="addNewPath()">Add New Path</button>
</span>
<li class="list-group-item" data-ng-repeat="choice in path.choices">
<span>
<span class="col-sm-2">
<select class="form-control" ng-model="choice.type" name="item" ng-options="item for item in selectOptions">
</select>
</span><br>
<span class="col-sm-9">
<input class="form-control" type="text" ng-model="choice.name" name="value" placeholder="Enter mobile number">
</span>
<button class="btn btn-danger" ng-click="removeChoice(path, choice.id)" ng-if="choice.id!=index">-</button>
<button class="btn btn-danger" ng-click="addNewChoice(path)" ng-if="choice.id===index">+</button>
</span>
</li>
</ul>
<br>
<button class="btn btn-primary" ng-click="addNewChoice(path)">Add fields</button>
</form>
<br>
<br>
<div id="choicesDisplay">
<!-- {{ choices }} -->
{{path}}
</div>
</div>
</body>

The issue is with choices object. As you are using same instance in multiple objects so as new table created data get copied.
The solution of this is to create new instance of choices when new table gets created using angular.copy
NOTE: I didn't understand why you added "Add Fields" outside the list as it doesn't make any sense when you create new tables dynamically.
I have made few changes in the code kindly refer below.
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.selectOptions = ["Mobile",
"Office",
"Home"
];
$scope.choices = [{"id": 1,"type":"Mobile","name":""},
{"id": 2,"type":"Mobile","name":""}];
$scope.path = [{"NumPath":1, 'path':angular.copy($scope.choices)}];
$scope.colNum=1;
$scope.addNewChoice = function(path) {
var newItemNo = path.path.length;
path.path.push({'id':++newItemNo, "type":"Mobile","name":""});
};
$scope.addNewPath= function() {
var NumPath=$scope.path.length;
console.log($scope.path.length)
$scope.colNum=NumPath+1;
$scope.path.push({"NumPath": NumPath+1,'path':angular.copy($scope.choices)});
};
$scope.removeChoice = function(id, path) {
path.splice(id-1, 1);
// re-initialize choice id
angular.forEach(path, function(o, index){
o.id = index+1;
})
};
});
<html>
<head>
<link rel="stylesheet" type="text/css" href="createQuiz.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.min.js">
</script>
<script src="quizMgmt.js"></script>
</head>
<body>
<div ng-app="angularjs-starter" ng-controller="MainCtrl">
<ul class="list-group" data-ng-repeat="path in path">
<span>
<h1 ng-model="colNum" >Path {{colNum}}</h1>
<button class="btn btn-primary" ng-click="addNewPath()">Add New Path</button>
</span>
<li class="list-group-item" data-ng-repeat="choice in path.path">
<span>
<span class="col-sm-2">
<select class="form-control" ng-model="choice.type" name="item" ng-options="item for item in selectOptions">
</select>
</span><br>
<span class="col-sm-9">
<input class="form-control" type="text" ng-model="choice.name" name="value" placeholder="Enter mobile number">
</span>
<button class="btn btn-danger" ng-click="removeChoice(choice.id, path.path)" ng-if="choice.id!=path.path.length">-</button>
<button class="btn btn-danger" ng-click="addNewChoice(path)" ng-if="choice.id===path.path.length">+</button>
</span>
</li>
<br/>
<br/>
<button class="btn btn-primary" ng-click="addNewChoice(path)">Add fields</button>
</ul>
<br>
<br>
<br>
<div id="choicesDisplay">
<!-- {{ choices }} -->
{{path}}
</div>
</div>
</body>
Good day :)

Related

Only one model working?

I have this weird issue where only one of my models are actually working. The only model that's updating is "toDo" as it repeats underneath the form, but "clicked" nor
"addToDo" are updating or being clicked:
using mvc
<head>
<title>ToDo</title>
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Scripts/Controllers/ToDoController.js"></script>
</head>
<div class="container">
<div ng-app="myApp" ng-controll="myCtrl">
<form>
<div class="form-group">
<label for="toDoItem">To Do</label>
<input type="text" class="form-control" id="toDoItem" placeholder="Enter your To-Do" ng-model="toDo"/>
<button type="button" class="btn btn-default" ng-click="addToDo()">Add To Do</button>
</div>
</form>
<p>ToDo: {{toDo}}</p>
<p>Clicked: {{clicked}} </p>
</div>
var app = angular.module('myApp', []);
app.controller('myCtrl',
function($scope) {
$scope.toDo = "";
$scope.clicked = false;
$scope.toDoArray = {};
$scope.addToDo = function() {
scope.toDoArray.push($scope.toDo);
$scope.clicked = true;
alert("To Do Added");
}
});
https://jsfiddle.net/npq5kc3h/
fiddle
You have some issues
You have a typo in your HTML:
<div ng-app="myApp" ng-controll="myCtrl">
^
You're not using the right $scope variable
scope.toDoArray.push($scope.toDo);
^
Your model toDoArray must be initialized as an array
$scope.toDoArray = {};
^
Snippet
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.toDo = "";
$scope.clicked = false;
$scope.toDoArray = [];
$scope.addToDo = function() {
$scope.toDoArray.push($scope.toDo);
$scope.clicked = true;
alert("To Do Added");
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<div class="container">
<div ng-app="myApp" ng-controller="myCtrl">
<form>
<div class="form-group">
<label for="toDoItem">To Do</label>
<input type="text" class="form-control" id="toDoItem" placeholder="Enter your To-Do" ng-model="toDo" />
<button type="button" class="btn btn-default" ng-click="addToDo()">Add To Do</button>
</div>
</form>
<p>ToDo: {{toDo}}</p>
<p>Clicked: {{clicked}} </p>
</div>

How can I store an array of chat messages in local storage and how can I retrieve them back in angularjs?

Iam working with chat application.Here I have to store the messages in local storage those entered by individual user as well as group messages also.So I want to use local storage inorder to store the messages so that when I click on the particular user,previous messages sent by that user has to be shown.Iam strucked at writing code for this.How can I implement this code in javascript?
Here is my entire code:
var grp = angular.module("grpApp", [])
.config(function ($interpolateProvider) {
$interpolateProvider.startSymbol('{|');
$interpolateProvider.endSymbol('|}');
})
.directive('scrollBottom', function () {
return {
scope: {
scrollBottom: "="
},
link: function (scope, element) {
scope.$watchCollection('scrollBottom', function (newValue) {
if (newValue) {
$(element).scrollTop($(element)[0].scrollHeight);
}
});
}
}
})
.controller("grpCtrl", function ($scope) {
document.getElementById("name").innerHTML = "Group";
$scope.friendsList = ["Devi", "Teja", "Sneha", "Srujana"];
$scope.msgdata = [];
var d = new Date();
$scope.time = d.toLocaleString();
console.log("hlooo" + $scope.time);
//$scope.uname=JSON.parse($stateParams.uname);
document.getElementById("clear").addEventListener("keyup", function (event) {
if (event.keyCode == 13) {
document.getElementById("submitmsg").click();
}
});
$scope.send = function () {
document.getElementById("submitmsg").disabled = false;
var retData = localStorage.getItem("storedData");
console.log("hiieeee" + retData);
var retrieveData = JSON.parse(retData);
console.log("heloooo" + retrieveData);
$scope.msgdata.push(retrieveData);
$scope.msgdata.push($scope.message + " " + " " + $scope.time);
$scope.message = "";
console.log("hi" + $scope.msgdata);
}
$scope.showGrp = function () {
document.getElementById("name").innerHTML = "Group";
$scope.msgdata = [];
var preData = $scope.msgdata;
localStorage.setItem("storedData", JSON.stringify(preData));
}
$scope.frndgrp = function (frnd) {
document.getElementById("name").innerHTML = frnd;
$scope.msgdata = [];
var preData = $scope.msgdata;
localStorage.setItem("storedData", JSON.stringify(preData));
}
});
<div class="container-fluid">
<div class="row content">
<div class="col-sm-4 sidenav" id="divlength" style="height:600px;overflow-y:scroll">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search friend.." ng-model="search">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
<br>
<button class="btn btn-primary btn-lg" style="width:50%" ng-click="showGrp()">Group</button>
<br>
<br>
<div class="nav nav-pills nav-stacked" ng-repeat="frnd in friendsList|filter:search">
<a class="btn btn-primary" style="width:50%" ng-bind="frnd" ng-click="frndgrp(frnd)"></a>
<br>
<br>
</div>
<br>
</div>
<div class="col-sm-8" style="height:100px">
<h4 align="center" id="name" style="font-weight:bold"></h4>
<footer id="wrapper">
<div class="chatbox">
<div class="chatBox" scroll-bottom="msgdata" id="clearmsg">
<div ng-repeat="item in msgdata track by $index"><span class="btn" id="msg" style="background-color:lightgreen;color:black; margin-bottom:5px" ng-bind="item"></span>
</div>
</div>
</div>
<div class="input-group add-on" style="width:100%;">
<input class="form-control usermsg chatTextField" placeholder="Type a message" name="srch-term" type="text" ng-model="message" id="clear" required>
<div class="input-group-btn">
<button class="btn btn-success" type="submit" style="float:right" id="submitmsg" ng-click="send()" ng-disabled="!message"><span class="glyphicon glyphicon-send"></span></button>
</div>
</div>
</footer>
</div>
</div>
</div>

Adding Angular UI Datepicker dynamically

In my project I need to add dynamic amount of datepickers to the page.
I tried to do it this way (Plunker):
Script:
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.openDatePicker = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {
formatYear: "yy",
startingDay: 1,
format: "shortDate"
};
$scope.details = [{
"parameterValue": "2015-08-12"
}, {
"parameterValue": "2015-08-12"
}, {
"parameterValue": "2015-08-12"
}, {
"parameterValue": "2015-08-12"
}];
});
HTML:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.3.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="script.js"></script>
</head>
<body>
<div ng-controller="MainCtrl">
<form name="detailsForm" novalidate ng-submit="submitForm(detailsForm.$valid)">
<div ng-repeat="item in details" class="input-group">
<input ng-model="item.parameterValue" type="text" class="form-control" id="datePickerItem" datepicker-popup="shortDate"
is-open="opened" datepicker-options="dateOptions" current-text="Today" clear-text="Clear" close-text="Close" ng-readonly="false" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDatePicker($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
</form>
</div>
</body>
</html>
The problem is that when I try to open one datepicker, all of them are opened (logically, as they share the same $scope.opened variable). Also when I close them and try to open them again, nothing happens.
Is there a elegant way to achieve this?
Thanks.
All of your datepickers have id="datePickerItem".
The id attribute must be unique in html. Try this instead:
id="datePickerItem_{{$index}}"
This will add the ng-repeat's current index to the id, so you can be relatively certain your id's are unique. This should also prevent all the datepickers from opening at the same time.
Also, you're using one and the same opened variable for all datepickers.
Try this instead:
<div ng-repeat="item in details" class="input-group">
<input ng-model="item.parameterValue" type="text" class="form-control"
id="datePickerItem_{{$index}}" datepicker-popup="shortDate"
is-open="opened[$index]" datepicker-options="dateOptions" current-text="Today"
clear-text="Clear" close-text="Close" ng-readonly="false" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDatePicker($event, $index)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
And:
$scope.opened = [];
$scope.openDatePicker = function($event, index) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened[index] = true;
};
Just make sure you set $scope.opened[index] to false, in case you close the datepicker.
try this:
$scope.open = function($event,opened) {
$event.preventDefault();
$event.stopPropagation();
$scope[opened] = true;
};
and in your html
ng-click="open($event, 'nameOfYourModel')"
why not bind opened on the repeat object?
like:
<div ng-repeat="item in details" class="input-group">
<input ng-model="item.parameterValue" type="text" class="form-control"
id="datePickerItem_{{$index}}" datepicker-popup="shortDate"
is-open="item['opened']" datepicker-options="dateOptions" current-text="Today"
clear-text="Clear" close-text="Close" ng-readonly="false" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDatePicker($event, item)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
and in controller:
$scope.openDatePicker = function($event, item) {
$event.preventDefault();
$event.stopPropagation();
if(item.opened){
item.opened = !item.opened;
} else{
item.opened = true;
}
};

AngularJS : How to make dynamic field button only for last button?

In the dynamic input field is there any option to implement plusSign = true only for the last item ?
(function() {
var app = angular.module('managementApp', []);
// var app = angular.module('managementApp', ['ngRoute']);
app.controller('phonebookController', function($scope, $http) {
$scope.dynamicField = function(buttonStatus, inputIndex) {
if (!buttonStatus) {
$scope.currentContact.contacts.push({
"phone": ""
});
} else {
$scope.currentContact.contacts.splice(inputIndex, 1);
}
};
$scope.currentContact = [{
"phone": "07875 506 426"
}, {
"phone": "+91 9895 319991"
}, {
"phone": "+44 7875 506 426"
}];
$scope.dynamicField = function(buttonStatus, inputIndex) {
if (!buttonStatus) {
$scope.currentContact.push({
"phone": ""
});
} else {
$scope.currentContact.splice(inputIndex, 1);
}
};
$scope.checkIndex = function(totalCount, indexCount) {
indexCount++;
// alert(indexCount);
/*if (totalCount === indexCount) {
//alert("last one");
$scope.plusSign = true;
}else{
$scope.plusSign = false;
}*/
};
});
})();
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="managementApp">
<div class="row" ng-controller="phonebookController">
<div class="form-group" ng-repeat="contact in currentContact" ng-init="checkIndex(currentContact.length, $index);">
<label for="contact-number3" class="col-sm-3 control-label">Contact number {{$index + 1 }}</label>
<div class="col-sm-9">
<div class="input-group">
<input type="tel" class="form-control" placeholder="Contact number {{$index + 1 }}" ng-model="contact.phone">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-init="plusSign = true"
ng-click="plusSign = !plusSign; dynamicField(plusSign, $index);">
<i class="glyphicon " ng-class="plusSign ? 'glyphicon-plus' : 'glyphicon-minus'"></i>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
You can use $last inside ng-repeat which is true if the repeated element is last in the iterator. Or you can do it with css only with .row:last-of-type {/**/}.
check $last in your function for example:-
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="managementApp">
<div class="row" ng-controller="phonebookController">
<div class="form-group" ng-repeat="contact in currentContact" ng-init="checkIndex($last);">
<label for="contact-number3" class="col-sm-3 control-label">Contact number {{$index + 1 }}</label>
<div class="col-sm-9">
<div class="input-group">
<input type="tel" class="form-control" placeholder="Contact number {{$index + 1 }}" ng-model="contact.phone">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-init="plusSign = true"
ng-click="plusSign = !plusSign; dynamicField(plusSign, $index);">
<i class="glyphicon " ng-class="plusSign ? 'glyphicon-plus' : 'glyphicon-minus'"></i>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
controller method
$scope.checkIndex = function(last) {
(last === true)
$scope.plusSign = true;
else
$scope.plusSign = false;
};

How to add HTML contents Dynamically on Button Click Event with AngularJS

I need to add HTML content on Button Click event using AngularJS. Is it possible??
My index.html
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
</div>
</div>
I want to add Nos. of HTML divs as per quantity added dynamically..
myApp.js
angular.module("myApp", []).controller("AddQuestionsController",
function($scope) {
$scope.myData = {};
$scope.myData.questionNos = "";
$scope.myData.doClick = function() {
//Do Something...????
};
});
It should be possible. I would data-bind your Divs to viewModel elements, and in your doClick function create the viewModels.
I would avoid directly creating Html in your viewModel.
For example:
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
<div ng-repeat="q in myData.questions">
<!-- BIND TO Q HERE -->
</div>
</div>
</div>
And in doClick:
$scope.myData.doClick = function() {
var newQuestions = getNewQuestionViewModels($scope.myData.questionNos);
for (var i = 0; i < newQuestions.length; i++) {
$scope.myData.questions.push(newQuestions[i]);
}
};
You have to store questions in collection and do repeat.
DEMO
HTML:
<div>
<input type="text" ng-model="data.qcount">
<button type="button" ng-click="data.add()">Add</button>
</div>
<div>
<div ng-repeat="q in data.questions track by $index">
<pre>{{ q | json }}</pre>
</div>
</div>
JS:
$scope.data = {
questions: [],
qcount: 0,
add: function() {
var dummy = {
'title': 'Q title',
'body': 'Q body'
},
newQ = [];
for (var i = 0; i < $scope.data.qcount; ++i) {
newQ.push(dummy);
}
$scope.data.questions = $scope.data.questions.concat(newQ);
$scope.data.qcount = 0;
}
};

Categories