Is using ng-init for bind once valid in angular js? - javascript

i have a collection of values whose structure lets assume to be
var a = [{id:1, value:12, name="one"}, {id:2, value:34, name="two"},...]
i wanted to display this in a series of controls so that user can change the values. but with that i also wanted to display original values which obviously shoudn't change.
i found out a way that is working and my code is something like this using ng-init
<div ng-repeat="p in a">
<div class="control-group" ng-if="p.value>0">
<label class="control-label" ng-bind="p.name"></label>
<div class="controls controls-row" ng-init="v=p.value">
<input class="span1" value="{{v}}"/>
<input type="number" ng-model="p.value" class="span2" />
</div>
</div>
</div>
being a complete newbie in angularjs i dont know what implications this might have as i have very little experience in thinking about $watch and performance.
Is it ok to do so?

but with that i also wanted to display original values which obviously shoudn't change.
Use angular.copy(/* array */). It will create new copy (instance) of old array.
BTW a collection must be defined as $scope.a
Demo Fiddle

Related

Jquery get values from dynamically generated input texts

Jquery get values from dynamically generated input texts
This is an example of what I am trying to achieve. Let me put the html code and describe afterwards
<div class="col-xs-3 ">
<label for="pointMap[0]-value">firstkey</label>
<input type="text" id="pointMap[0]-value" name="pointsValueMap[firstkey]" value="value1">
</div>
<div class="col-xs-3 ">
<label for="pointMap[1]-value">secondkey</label>
<input type="text" id="pointMap[1]-value" name="pointsValueMap[secondkey]" value="value2">
</div>
I would like to have all the values of however many of these kinds of input type text id (pointMap[i]-value). Please also suggest if there is a better way than having them an array when collected. My mind is blank on what should I be looping against, in a for loop, I am unable to find a terminating condition (size of these input texts).
Since you are using jQuery. You can use the attribute contains selector. There is whole list of such selectors in jQuery.
You can store values of such inputs in an array like this
var inputStore = []; //Where you want to store the values
$("input[name*=pointsValueMap]").each(function(){ //Will check for inputs with name containing pointsValueMap
inputStore.push($(this).val())
});

Create JSON on HTML basis and vice-versa

I have hierarchical structure of <select>/<input> based elements, which can be formed into (logical) groups. In other words, i have logical-tree where every node represented by (three) <select>/<input>.
Here is how HTML looks like (all extra elements like buttons deleted):
<div class="conditions-group logical-or">
<div class="conditions">
<div class="conditions-group logical-and">
<div class="conditions">
<div class="condition row">
<div class="metric">
<select class="form-control"></select>
</div>
<div class="operator">
<select class="form-control "></select>
</div>
<div class="value">
<input value="" class="form-control">
</div>
</div>
<div class="condition row">
<div class="metric">
<select class="form-control"></select>
</div>
<div class="operator">
<select class="form-control "></select>
</div>
<div class="value">
<input value="" class="form-control">
</div>
</div>
</div>
<div class="condition row">
<div class="metric">
<select class="form-control"></select>
</div>
<div class="operator">
<select class="form-control "></select>
</div>
<div class="value">
<input value="" class="form-control">
</div>
</div>
</div>
</div>
My aplication is C# ASP-NET MVC. I use bootstrap to make this looking good. And i have some JS-logic for creating this by user. This HTML-code is just example that created by me.
I need to store this structre and be able to build HTML back from stored data (so user can comeback and see his structure).
So i understood that i need to use JSON to store.
Here is my questions:
What is the better way to achive my goal? I need use some JS-library, right? Could you please make my clear practical advice what to use in this case and why.
You don't have to use JSON, but you do need to serialize it somehow. JSON can be a fairly clean method.
There are some libraries out there that will do this, but at a cursory glance, none of them seemed super well supported, so you might want to avoid.
In this case, it seems fairly straight and I would probably go with a more direct approach which you do it more or less by hand.
Starting with, since it looks like you have metric, operator, and value in each, I would start with those in your object:
{
rows: [
{ metric: 'someValue', operator: 'someValue', value: 'someValue' },
// .. more as necessary
]
}
I would build the object as a POJO (plain old JavaScript object) and then use JSON.stringify() to convert it to JSON.
With your data, you could basically just loop through and output your HTML:
function render(rows) {
rows.forEach(({ metric, operator, value }) => {
// create elements based on these value
});
}
For saving the data, there are two approaches:
parse the HTML and turn it into a JSON object after the fact
keep the data as an object, update it, and then re-render the page based off of it
I prefer the second method. Instead of making HTML directly, have one data object and when you make changes, update that object and just call your render() method to re-render. This means you don't have to parse the HTML when you go to save.
It will also simplify the tool you mentioned to allow uses to add this, as all it'll have to do instead is rows.push({ metric: 'defaultValue', operator: 'defaultValue', value: 'defaultValue' }).
The only other thing is to add an onChange() to each input. When they change, figure out which row it is (get the .row parent and figure out what index it is relative to its siblings, that'll be the same index for the rows object) and field (just get the class name) and then just update the appropriate value.
This kind of render-based-off-data is also what libraries like React, Angular and Vue do. Depending on your project, you may consider leveraging one of them to help with things as well (though if the project is small, its perfectly doable without).

AngularJS ng-repeat input

I am trying to make comments functionality using Angular js. The problem is that when i want to write a comment for a post, the text is also writing inside other input elements (comments). I write a text inside one input, but it writes it in all inputs
So for example same is happening with this code
<div class="comments" ng-repeat="articles in [1,2,[4,5,6]]">
<div ng-repeat="comments in articles">
<div>
<input type="text" ng-model="$parent.new">
</div>
</div>
if i use new instead of $parent.new i get undefined, but when i use $parent.new and i write in one input, it also writes in other inputs.
The issue is that you are assigning all of the inputs to the same model, so your inputs are all in sync with the same object.
What you need is to assign each input to a different model. I'm guessing you need these models to be dynamic, so you should use an array as your model and track your ng-repeat by $index like so:
<div ng-repeat="comments in articles track by $index">
<div>
<input type="text" ng-model="arr[$index]">
<span ng-if="arr[$index]">
{{arr[$index]}}
</span>
</div>
</div>
Now, in your controller, you can initialize the empty arr like so:
$scope.arr = [];
Now, your inputs will be in sync with $scope.arr depending on the index they were in.
Try out this jsfiddle for an example.
This is because you've giving same model (ng-model="$parent.new") for all of the inputs What you should do to avoid this problem is assign different model to each input element. Something like
<div class="comments" ng-repeat="articles in [1,2,[4,5,6]]">
<div ng-repeat="comments in articles">
<div>
<input type="text" ng-model="comments">
</div>
</div>
Change ng-model of input to
<input type="text" ng-model="comments.comment">

Angular1: How to reflect ng-model errors on another element?

I have a directive with the following template
<div>
<span class="label">My Label</span>
<input ng-model="name" required>
</div>
I want the label to be painted red when the input field is invalid.
How can I do that?
Currently I have another directive to sync all the errors from ngModelCtrl to the wrapping div
<div add-all-errors>
...
</div>
And the directive's link function does something like this:
const ngmodel = $element.find('[ng-model]').controller('ngModel');
$scope.$watch(()=>ngmodel.$error, addAllClasses, true);
Where addAllClasses simply makes sure the correct classes appear on the element..
I also tried just adding the same ng-model
<div ng-model="name">
...
</div>
But did not see the classes there..
any better way to do this?
This is why we use the angularjs form... I'm really not sure why people are against using a very handy feature.
I've made a plunker for you.
https://plnkr.co/edit/bGOcQjWzlRq2aTYZUYNm?p=preview
<form name="form">
<span ng-class="{red: form.name.$invalid}">Name:</span>
<input name="name" ng-model="name" required>
</form>
A little more insight of what's going on. form is added to the scope auto magically by angularjs by it's name. In this case, I named it form, however it can be any name.
Now form is an ngForm Object and adds all input field into it by their name attributes. This way we can do form.name to get another object similar to the ngForm Object. We can then use $invalid or $valid properties with ng-class.
ngForm is pretty powerful and is loaded with many cool properties and methods. Just call console.log(scope.form); You will need to put in a method and add it to ng-change to see updates.

Create object from Form inputs to pass to controller method

I have an array of jobs in my js/controller. Each job object in the array has attributes like jobName, company, city, etc. Is it possible by submitting a form with inputs for the attributes to make it into a job object and then push it into the jobs array in the controller?
So for example, I have a form and I input Software Developer, StackOverflow, NY. Can I wrap the form into an object with the correct attributes and then pass it into the array of jobs in the controller to view it on the view?
Here's my form code so far...
<form name="jobForm" ng-submit="list.addJob(jobForm)">
<div class="form-group" id="test">
<label>Job Name:</label>
<input ng-model="jobName" type="text"/>
</div>
<div>
<label>Company:</label>
<input ng-model="companyDescription" type="text"/>
<div><button type="submit">Enter job entry</div>
</div>
<!-- this is where the live preview is. ng-model in the input binds it to these values -->
<blockquote>
<h4><u>Live Preview</u></h4>
<b>Job Name:</b> {{jobName}}
<div><b>Company:</b>{{companyDescription}}</div>
</blockquote>
</form>
So I want to create a JOB object using the jobName and companyDescription's inputs as the object's name and company attribute. How can I do this? OR am i using a wrong approach. Thank you for the help!
For starters there is a golden rule that ng-model should always be an object property to begin with ... or you can run into lots of child scope problems due to inheritance
So your whole issue is simplified by not using individual scope properties and using one object for all the ng-model in the form to begin with
$scope.job={}
<input ng-model="job.jobName" type="text"/>
<input ng-model="job.companyDescription" type="text"/>
Then when you need to send that to server it is as simple as doing
$http.post(url, $scope.job).then(func....
or pushing to another array
$scope.allJobs.push($scope.job);
$scope.job = {} // reset

Categories

Resources