AngularJS creating json from ng-repeat - javascript

Inspired from this codepen I used a JSON file to load some basic input fields and toggles. When the user change something and press save, I would like to save these new property values in a new JSON object with same property names.
My code looks the this
JS
.controller('page', function($scope, templateSettingsFactory, savedSettingsFactory) {
$scope.template = templateSettingsFactory;
$scope.saved = savedSettingsFactory;
$scope.saveSettings = function(){
var temp = $scope.template;
var jsonObj = {};
for(var key in temp){
jsonObj[key]=temp[key];
}
$scope.saved.$add(jsonObj);
};
});
HTML
<label ng-repeat="item in template">
<input type="text" placeholder="{{item}}">
</label>
<button class="button" ng-click="saveSettings()">Save</button>
The problem is that calling the saveSettings() don't get the updated property values of $scope.template - perhaps it's not doing two-way binding?

You need to use ng-model on your form elements to bind their input to the scope.
<input type="text" ng-model="item.property">
Here is an example of binding to a single object with arbitrary keys:
<div ng-repeat="(key,value) in template">
<div>{{key}}</div>
<input type="text" ng-model="template[key]"/>
</div>
https://docs.angularjs.org/api/ng/directive/ngModel

Related

ng model not working

I am trying to set the value using ng-model (passing values via function).
My codes look like
Input tag:
<input name="comments" ng-model="comments" class="form-control" type="text">
Grid Table :
<tr ng-repeat="value in values">
<td><input type="radio" ng-click="callvalues(value.CUSTID);"></td>
Angularjs code:
$scope.callvalues = function($scope,custID){
alert("custID");
};
I am getting custID is not defined. I try to hardcore values
$scope.callvalues = function($scope,custID){
$scope.comments = "122";
};
NO error in console but it's also not working.
remove $scope parameter from your function
from
$scope.callvalues = function($scope,custID){
to
$scope.callvalues = function(custID){
If what you mean is click in radio button and alert value you can try this code
$scope.callvalues = function(custID){
alert(custID);
$scope.comments = custID;
};
plnkr
https://plnkr.co/edit/CYi3e2D0xLkWksr9p4y8?p=preview
Grid Table
<tr ng-repeat="value in values">
<td><input type="radio" ng-model="selectedRadio" ng-value="value.CUSTID" ng-click="callvalues(selectedRadio);"></td>
Controller
$scope.callvalues = function(custID){
//console.log($scope.selectedRadio);
alert(custID);
};
You don't need to pass $scope as method argument. You can read it's values in any method inide of Controller.
$scope.callvalues = function(custID){
alert("custID");
$scope.comments = custID;
};

Tracking many dynamic forms with ng-model

I'm generating dozens of forms on my page. Each form has several parameters (not the same for each form). I'm generating my forms as such (simplified):
<div ng-repeat='module in modules'>
<form ng-submit='submitModule(module)'>
<div ng-repeat='arg in module.args'>
<input ng-model='models[module.name][arg.name]' id="{{ arg.name }}">
</div>
</form>
</div>
You can see I'm trying to assign a unique ng-model to each input parameter by using a two dimensional array models[module.name][arg.name].
Because I am planning on submitting this as JSON, the idea was that I could just do models[some_module] in my controller to get the full JSON, and then just post along.
Unfortunately this isn't working, when trying models['test_module'] I get undefined, instead of my object. There are no errors elsewhere in the code, I've tested extensively. The problem comes from the use of multi-dimensional arrays here which is apparently a big no-no.
How should I handle my situation? IE: several forms, several inconsistent parameters, and a need to POST every param together as JSON.
EDIT: For info, my controller looks like:
angular.module('app')
.controller('InputCtrl', function($scope, InputSvc) {
$scope.models = {};
InputSvc.list().success(function(modules) {
$scope.modules = modules;
$scope.models['test_module'] = {}
});
$scope.submitModule = function(module) {
console.log($scope.models['test_module']);
};
});
Perhaps you could give each form a controller so the model is scoped to the form instance rather than the parent:
<div ng-repeat='module in modules'>
<form ng-controller="FormCtrl" ng-submit='submitModule(module)'>
<div ng-repeat='arg in module.args'>
<input ng-model='formData[arg.name]' id="{{ arg.name }}">
</div>
</form>
</div>
Then your FormCtrl would have the submit method and the model:
angular.module('app')
.controller('FormCtrl', function($scope) {
$scope.formData = {};
$scope.submitModule = function(module) {
console.log($scope.formData);
};
});
Here is a Codepen

creating property dynamically in ng-model

<div class="form-group" data-ng-repeat="choice in choices">
<input type="text" ng-model="user.subjectname[$index]"
name="subject" ng-required="true" placeholder="Enter a subject name">
</div>
As I am creating this input field dynamically using ng-repeat, if I used ng-model=user.subjectname, the input text for some reason was same in all the fields, I searched over the internet and found ng-model="user.subjectname[$index]" being used and it worked.
However, i am not able to understand
what it exactly means. ?
2.If it's array or an object. ?
It shows up as object in console. ?
If it's object, why does it have an index?
Also, as we can iterate over object vals using this format:
ng-repeat="(key,val) in user.subjectname"{{val}}
Why did it not work?
neither did ng-repeat="subject in user.subjectname"{{subject}}
Can I please get directions as I am very confused about it at the moment.
It is an array. When you do :
var test = []; console.info(typeof test);// You would get object as arraysa re also object in Javascript.
Here you are passing $index of choice in choices to subjectname array. Which is fine. After populating subjectname with some of the data, you can use ng-repeat like
ng-repeat = "subject in user.subjectname"
Also initialize user.subjectname = []; in controller
<form class="idea item">
<div ng-repeat="(key, value) in items[0]" >
<label>{{key}}</label>
<input type="range" ng-model="items[0][key]" min="0" max="15"/>
</div>
<input type="submit" ng-click="save()" />
<pre>{{items | json}}</pre>
var app = angular.module('my-app', [], function () {
})
app.controller('AppController', function ($scope) {
$scope.items = [{"red": 14, "green": 12, "orange": 1, "yellow": 11, "blue": 9}];
})

How to add multiple items to a list

I'm building an app where users can add items to a list and I decided, for the sake of learning, to use Angular (which I'm very new to). So far, I've been able to successfully add a single item to that list without any issues. Unfortunately, whenever I try to add more than one without a page refresh, I get an error - specifically a "Undefined is not a function."
I've spent more time than I care to think about trying to resolve this issue and I'm hoping an expert out there can give me a hand. Here's what I have so far:
Controllers:
angular.module('streakApp')
.controller('StreakController', function($scope) {
// Removed REST code since it isn't relevant
$scope.streaks = Streak.query();
// Get user info and use it for making new streaks
var userInfo = User.query(function() {
var user = userInfo[0];
var userName = user.username;
$scope.newStreak = new Streak({
'user': userName
});
});
})
.controller('FormController', function($scope) {
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
$scope.newStreak = {};
};
});
View:
<div class="streaks" ng-controller="FormController as formCtrl">
<form name="streakForm" novalidate >
<fieldset>
<legend>Add an activity</legend>
<input ng-model="newStreak.activity" placeholder="Activity" required />
<input ng-model="newStreak.start" placeholder="Start" type="date" required />
<input ng-model="newStreak.current_streak" placeholder="Current streak" type="number" min="0" required />
<input ng-model="newStreak.notes" placeholder="Notes" />
<button type="submit" ng-click="addStreak(newStreak)">Add</button>
</fieldset>
</form>
<h4>Current streaks: {{ streaks.length }}</h4>
<div ng-show="newStreak.activity">
<hr>
<h3>{{ newStreak.activity }}</h3>
<h4>Current streak: {{ newStreak.current_streak }}</h4>
<p>Start: {{ newStreak.start | date }}</p>
<p>Notes: {{ newStreak.notes }}</p>
<hr>
</div>
<div ng-repeat="user_streak in streaks">
<!-- Removed most of this for simplicity -->
<h3>{{ user_streak.fields }}</h3>
</div>
</div>
Could you post the html of StreakController too? Your solution works fine in this fiddle:
http://jsfiddle.net/zf9y0yyg/1/
.controller('FormController', function($scope) {
$scope.streaks = [];
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
$scope.newStreak = {};
};
});
The $scope inject in each controller is different, so you have to define the "streaks" in FormController.
Your problems comes from :
.controller('FormController', function($scope) {
// Works for single items, not for multiple items
$scope.addStreak = function(activity) {
$scope.streaks.push(activity);
^^^^^^
// Streaks is initialized in another controller (StreakController)
// therefore, depending of when is instantiated StreakController,
// you can have an error or not
$scope.newStreak = {};
};
});
A better design would be to implement a StreakService, and to inject that service in the controller you need it. Of course, initializing $scope.streaks in FormController will make your code work, but that's not the responsibility of FormController to initialize this data.
I assume FormController is a nested controller of StreakController, so they share the same scope.
if that works for single object, it should work for mulitiple objects, the problems is you can't just use push to push an array of object to the streaks, you can for loop the array and add them individually or use push.apply trick. I thought the reason of Undefined is not a function. is because the Stack.query() return an element instead of an array of elements so, the method push doesn't exists on the $scope.streaks.
http://jsbin.com/jezomutizo/2/edit

Read content from DOM element with KnockoutJS

The goal
Read content from DOM element with KnockoutJS.
The problem
I have a list of products in my HTML. The code is something like this:
<li>
<div class="introduction">
<h3>#Model["ProductName"]</h3>
</div>
<form data-bind="submit: addToSummary">
<input type="number"
placeholder="How much #Model["ProductName"] do you want?" />
<button>Add product</button>
</form>
</li>
When I click on <button>Add Product</button>, I want to send to KnockoutJS the text inside <h3></h3> of the element that was submitted.
The file to work with KnockoutJS is external and independent of HTML. It name is summary.js and the code is below:
function ProductReservation(id, name, unity, quantity) {
var self = this;
self.id = id;
self.name = name;
self.unity = unity;
self.quantity = quantity;
}
function SummaryViewModel() {
var self = this;
self.products = ko.observableArray([
new ProductReservation(1, "Testing", "kgs", 1)
]);
self.addToSummary = function () {
// Do Something
}
}
What I'm thinking about
HTML:
<li>
<div class="introduction">
<h3 data-bind="text: productName">#Model["ProductName"]</h3>
</div>
[...]
</li>
JS:
productName = ko.observable("text: productName");
But, of course, no success — this is not the correct context or syntax, was just to illustrate.
So I ask: what I need to do?
You're binding addToSummary via the submit binding. By default KO sends the form element to submit-bound functions.
So addToSummary should have a parameter -
self.addToSummary = function (formElement) {
// Do Something
}
You can pass additional parameters to this function (as described in KO's click binding documentation under 'Note 2'), or you could just add a hidden field to your form element and pull it from there.
<li>
<div class="introduction">
<h3>#Model["ProductName"]</h3>
</div>
<form data-bind="submit: addToSummary">
<input type="number" name="quantity"
placeholder="How much #Model["ProductName"] do you want?" />
<input type="hidden" name="productName" value="#Model["ProductName"]" />
<button>Add product</button>
</form>
</li>
Then in your knockout code you could use jQuery to process the form element to pull out the data -
self.addToSummary = function (formElement) {
var productName = $(formElement).children('[name="productName"]')[0].val();
var quantity= $(formElement).children('[name="quantity"]')[0].val();
// ...
self.products.push(new ProductReservation(?, productName, ?, quantity));
}
One strategy that has worked well in my experience is to implement a toJSON extension method that serializes your model (if you use a library like JSON.NET you can have a lot of control over what gets serialized and what does not).
Inside of the view where you initialize KnockoutJS, you could serialize your model and pass it into the KnockoutJS ViewModel you're creating (assuming :
Main view:
<script type="text/javascript">
var viewModel = new MyViewModel(#Model.ToJSON());
</script>
ViewModel:
function MyViewModel(options) {
this.productName = ko.observable(options.ProductName);
}

Categories

Resources