angularJS what's a good way to put dictionary in input - angularjs

I have a dictionary of data in the controller and I'm displaying it using ng-repeat. The key is the Title and the value is placed as the value field of an input. I want the user to be able to edit the values and then submit the form. What's the best way I can handle all the input? I've tried ng-model but I can't change the values of the dictionary directly so I'm leaning towards making another dictionary to store the new data. That doesn't seem very efficient though so I'm wondering if there's a better way.
edit: I have this interface and add some values.
export interface Iint {
[title: string] : string;
}
this is in the constructor
this.hashMap : Iint = {};
this.hashMap["Next Title"] = "data";
this.hashMap["Next Value"] = "more data;
In the html I want each of the values (data, more data) to appear in it's own input text box where the user can edit and change the values in the dictionary. I need validation and other things before the user can save and update the data so I'm unsure of if I should be making a duplicate array.

Check this example out. I implemented it in Angular v1 before you edited your answer.
https://plnkr.co/edit/9Y33BDQTngPZx2Vpx5Zz?p=preview
script.js
var app = angular.module('myApp',[]);
app.controller('MyCtrl', ['$scope', function($scope) {
$scope.dict = {
"Title1" : "Hello World !",
"Title2" : "Beautiful day",
"Title3" : "How about that!?"
};
$scope.submitForm = function() {
console.log($scope.dict);
alert(JSON.stringify($scope.dict));
};
}]);
index.html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<h1>Dictionary Inputs</h1>
<div ng-controller="MyCtrl">
<form name="myForm" ng-submit="submitForm()">
<ul>
<li ng-repeat="(key,val) in dict">
{{key}} : <input type="text" ng-model="$parent.dict[key]">
</li>
</ul>
<button type="submit"> Submit</button>
</form>
<br/>
<div>
$scope.dict : {{dict}}
</div>
</div>
</body>
</html>
Implementing it in Angular v2 might be on similar lines.

It is possible to get ngRepeat to iterate over the properties of an object using the following syntax:
<div ng-repeat="(key, value) in myObj"> ... </div>
Reference: https://docs.angularjs.org/api/ng/directive/ngRepeat#iterating-over-object-properties

Related

Angularjs Ng-init shows the same retrieved form values when passed through ng-repeat

Am having an issues with angularjs ng-init(). In my table called post, I have 3 rows inserted. For example
insert into post(id,title)values(1,'title1');
insert into post(id,title)values(2,'title2');
insert into post(id,title)values(3,'title3');
Now I have retrieved the records and pass it through ng-repeat and everything works fine.
My problem is the ng-init() function. when I passed the database values into a form inputs with ng-init initialized within the ng-repeat, its shows the last database values all through in the form inputs (Eg. 3, title3)
<input type='text' ng-model='title' ng-model='$parent.title' ng-init="$parent.title=post.title" >
if I add value attribute to the form (Eg. value={{post.id}}) it will show the correct form values on each row but when I click on submit button, the value attribute will not be submitted but it will rather pass the value to ng-init which keeps submitting only the last database records (Eg. 3, title3) irrespective of the form button on each row that was clicked.
I have attached the screenshot that shows how the ng-init displays only the last record in a form values instead of showing all records corresponding to each form rows
but I was expecting to have is the form below or a work around within the angularjs controller or equivalents
below is the code
<!doctype html>
<html>
<head>
</head>
<body ng-app='myapp'>
<div class="content" ng-controller='fetchCtrl'>
<div class="post" ng-repeat='post in posts'>
<form bind-to-scope='$parent' >
post Id<br>
<input type='text' ng-model='pid' ng-model='$parent.pid' ng-init="$parent.pid=post.id" >
<br>
post Title<br>
<input type='text' ng-model='title' ng-model='$parent.title' ng-init="$parent.title=post.title" >
<br>
<input type='button' id='but_save' value='Save' ng-click="submitButton()" >
</form>
</div>
</div>
</div>
<!-- Script -->
<script src="angular.min.js"></script>
<script>
var fetch = angular.module('myapp', []);
fetch.controller('userCtrl', ['$scope', '$http', function ($scope, $http) {
// Add new record
$scope.submitButton = function(){
var pid=$scope.pid;
//alert variables values that is all I want
alert(pid);
// do http thing here if you like
$http({
});
}
// Fetch post data scope goes here
</script>
</body>
</html>
You have few issues in your code: Here are few issues in your question
$parent is not required to bind the data
You have taken ng-model twice in each input which is wrong
Also, ng-model binds the data automatically, ng-init is not required.
Here is the solution:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="post in posts">
<form>
post Id<br>
<input type='text' ng-model='post.pid' >
<br> post Title<br>
<input type='text' ng-model='post.title'>
<br>
<input type='button' id='but_save' value='Save' ng-click="submitButton()">
</form>
</div>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.posts = [
{
"pid" : "1",
"title" : "title1"
},
{
"pid" : "2",
"title" : "title2"
},
{
"pid" : "3",
"title" : "title3"
},
]
$scope.submitButton = function(){
alert(angular.toJson($scope.posts))
}
});
</script>
</body>
</html>
Please run the above snippet
Here is a working DEMO

How to push an object array into an scop array?

In angular js How can I push an object array into an array.
Here is my code
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<h1 ng-repeat="x in records">{{x.Class}}
</h1>
<div ng-repeat="s in records.students">{{s.name}}</div>
<input ng-model="formdata.name" type="text" />
<input type="button" value="Save" ng-click="saveName(formdata)">
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [{"Class":"Class 8"}];
$scope.saveName = function(name)
{
$scope.records.students.push({"name":name});
}
});
</script>
</body>
</html>
how can I push into $scope.records.students here $scope.records is an array.
what mistake I am doing I am getting "Cannot read property 'push' of undefined"
Your records property on $scope has no property called students. Therefore, $scope.records.students is undefined. Undefined doesn't have any methods available. You should make sure students exists before pushing.
Also, be aware the ngModel passes by reference. In your original code, the {{s.name}} list will only ever show the text in the input because each element in students points towards the same underlying reference. You should dereference the string that saveName receives. I've done so in the code below, but try playing with it so you can see how it works.
Updated code:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<h1 ng-repeat="x in records">{{x.Class}}
</h1>
<div ng-repeat="s in records.students">{{s.name}}</div>
<input ng-model="formdata.name" type="text" />
<input type="button" value="Save" ng-click="saveName(formdata)">
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [{"Class":"Class 8"}];
$scope.saveName = function(name)
{
// Also, you need to derefence the object
// this is a quick and dirty way, try removing it and see
// what happens
var deRefName = JSON.stringify(name);
// Checks for the existence of students, if it doesn't exist
// sets students to an empty array
if (!($scope.records.students)) {
$scope.records.students = [];
}
$scope.records.students.push({"name":deRefName});
}
});
</script>
</body>
</html>
As the error denotes, there is no way you can access records.students since its an array, not an object.
You need to have records as either an object and inside it student as an array.
then you should be able to access $scope.records.students.
or use $scope.records as array and use index to access the particular object of it.

Lose the focus after inserting a letter

I have written a script which represent a json data in 2 ways: JSBin
<!DOCTYPE html>
<html>
<head>
<script src="https://handsontable.github.io/ngHandsontable/node_modules/angular/angular.js"></script>
</head>
<body ng-app="app">
<div ng-controller="Ctrl">
GUI:
<div ng-repeat="item in data">
<input ng-model="item.val">
</div>
<br><br><br>
Textarea:<br>
<textarea rows=10 cols=20 ng-model="dataString"></textarea>
</div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', '$filter', function($scope, $filter) {
$scope.data = [{val: "1"}, {val: "2"}];
$scope.$watch('data', function(data_new) {
$scope.dataString = $filter('json')(data_new);
}, true);
$scope.$watch('dataString', function(dataString_new) {
$scope.data = JSON.parse(dataString_new);
}, true);
}]);
</script>
</body>
</html>
Thus, modifying the value in GUI will change the string in the textarea (because of $watch('data'); and modifying the string in the textarea will change the GUI (because of $watch('dataString')).
However, the problem is that when we change the value in GUI, we lose the focus after inserting a letter.
Does anyone know how to amend this?
So the problem is that you are iterating over an array (ng-repeat) and changeing the items of the array. The items are removed from the DOM and new one are inserted because they are strings and thereby compared by value. This makes you loose focus.
It's pretty simple to fix though. Just track by index as the objects are in identical order.
Change:
<div ng-repeat="item in data">
To:
<div ng-repeat="item in data track by $index">

AngularJS NG-Repeat JSON

I apologize for this simple question. I've been scouring other questions and still can't get it to work.
I have a function returning some key/value pairs
function(data){
console.log(data.message);
}
Returns...
Object {name: "mpierce486", body: "asfsf", time: "1 second ago"}
I have the following when not logging to console...
$scope.message = data.message
Lastly, here's the markup. I'm using a Laravel app so I'm escaping the {{ with #. Nothing shows up and I know it's a simple mistake. Please assist! Thanks!
<div ng-app="myApp" ng-controller="messageCtrl">
<div ng-repeat="x in message" class="main-user-post">
<h1>#{{ x.body }}</h1>
</div>
</div>
I don't think you can do an ng-repeat on an object. Since it's already an object, not an array, you can access it directly, without ng-repeat.
<div ng-app="myApp" ng-controller="messageCtrl">
<div class="main-user-post">
<h1>#{{ message.body }}</h1>
</div>
</div>
your message variable is an object, not an array. So in your iteration, x will take the value of each object properties (body, name, time).
So either use a different approach, or transform your message to an array:
$scope.message = [data.message];
you can iterate through object properties with angular like this:
<div ng-app="myApp" ng-controller="messageCtrl">
<div ng-repeat="(key, value) in message" class="main-user-post">
<h1>#{{value}}</h1>
</div>
</div>
Create object array as below.
JSFiddle - https://jsfiddle.net/L7k6g7ua/ for reference w.r.t AngularJs -
Hope this helps!
<body ng-app="SampleApp">
<div ng-controller="messageCtrl">
<div ng-repeat="m in message" class="main-user-post">
<h1>{{m.body}}</h1>
</div>
</div>
</body>
var sampleApp = angular.module("SampleApp", []);
sampleApp.controller('messageCtrl', function($scope) {
var myObject = {
name: "mpierce486",
body: "asfsf",
time: "1 second ago"
};
var myArray = [];
myArray.push(myObject);
$scope.message = myArray;
});

Generate dynamic form input fields and collect field data in an array

I am stuck with this little task.
I need to generate form input fields dynamically by clicking 'add' button on the form.
The form is supposed to create DB table schema. So every input field is a DB table field name.
I am OK generating the fields dynamically but have trouble with gathering the actual data.
<form ng-controller="NewTableCtrl" ng-submit="submitTable()">
<input type='text' ng-model='table.title' placeholder='Title:'>
<input ng-repeat="field in fields" type='text' ng-model='table.fields' placeholder='Field:'>
<div>
<button type='submit'>Submit</button>
<button ng-click="addFormField()">Add</button>
</div>
</form>
.. and the controller
.controller('NewTableCtrl', function($scope) {
$scope.fields = [];
$scope.table = {};
$scope.addFormField = function () {
$scope.fields.push({});
}
$scope.submitTable = function () {
console.log($scope.table);
}
});
Looks simple. When I click 'Add' button it generates the new input field but it does it with the same model object (obveously). And that's where my misunderstanding lies. I thought that if I declare $scope.fields = [];in the controller then repeating field data will just go into the array. But it just echoes the input in every repeating input field. I understand now that this is how it is supposed to be with two way binding.
The reason I thought like this is by the analogy with an ordinary form submission where the repeating input field names become an array in the URL encoded form data.
So how do I solve this? The server needs to get an array of fields like this: fields: [field1, field2 ...] Do I need to generate input fields with different scope variable for each field? How do I do this?
Is this more complex then I thought and it needs to be a directive? If yes, please, show me how to do this.
Thanks.
Right now you are iterating $scope.fields. When you are adding a new field you push an empty object into $scope.fields, but every input's ng-model points to $scope.table.fields (which is non-existing until first input writes to it - then it will hold a string variable).
For this simple use case you could try:
app.controller('NewTableCtrl', function($scope) {
$scope.table = { fields: [] };
$scope.addFormField = function() {
$scope.table.fields.push('');
}
$scope.submitTable = function() {
console.log($scope.table);
}
});
And:
<input ng-repeat="field in table.fields track by $index" type='text' ng-model='table.fields[$index]' placeholder='Field:'>
Demo: http://plnkr.co/edit/6iZSIBa9S1G95pIMBRBu?p=preview
Take a look at this
Working Demo
html
<body>
<div ng-app=''>
<div ng-controller="questionCtrl">
<div>
<ul>
<li ng-repeat="elemnt in questionelemnt">
<div>
<div id={{elemnt.id}} style="display:inline" >
<span ng-model="elemnt.question" ng-hide="editorEnabled" ng-click="editorEnabled=true">
{{elemnt.question}}
</span>
<div ng-show="editorEnabled">
<input ng-model="elemnt.question" ng-show="editorEnabled" >
<button href="#" ng-click="editorEnabled=false">Done editing</button>
</div>
</div>
<div style="display:inline">
<span>
<input type="text" ng-model="elemnt.answer" placeholder="Answer" required/>
</span>
</div>
<span ng-hide="elemnt.length == 1">
<button ng-click="questionelemnt.splice($index, 1)">Remove</button>
</span>
</div>
<hr/>
</li>
<li>
<button ng-click="addFormField($event)">Add</button>
</li>
</ul>
</div>
<div>
<button ng-click="showitems($event)">Submit</button>
</div>
<div id="displayitems" style="visibility:hidden;">
{{questionelemnt}}
</div>
</div>
</div>
</body>
script
function questionCtrl($scope) {
var counter = 0;
$scope.questionelemnt = [{
id: counter,
question: 'Question-Click on me to edit!',
answer: ''
}];
$scope.addFormField = function ($event) {
counter++;
$scope.questionelemnt.push({
id: counter,
question: 'Question-Click on me to edit!',
answer: ''
});
$event.preventDefault();
}
$scope.showitems = function ($event) {
$('#displayitems').css('visibility', 'none');
}
}
Variation of tasseKATTs solution using a hashmap instead of an array.
This allows me to have a nice JSON object I can just for-in over in order to build my query filter.
http://plnkr.co/edit/CArP3Lkmn7T5PEPdXgNt?p=preview
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.3.0" src="//code.angularjs.org/1.3.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<style>
div{ margin: 1em;}
input{margin-left:1em;}
</style>
</head>
<body ng-controller="myCtrl">
<h2>Using a filter map tied to ng-model to create a filter object</h2>
<div ng-repeat="field in fields">
{{field}}<input ng-model=filters[field] />
</div>
<hr>
<h3>Filter</h3>
{{filters}}
<script>
var app=angular.module("app",[]);
app.controller("myCtrl",function($scope){
$scope.filters={};
$scope.fields=["name","address","phone","state"];
});
angular.bootstrap(document,["app"]);
</script>
</body>
</html>

Resources