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).
Related
i am loading handlebar templates in the two div locations(like add and edit tabs both are jsps) from the same page. so i have duplicate elements in the DOM object, since it is a template which is coming from server location. you can see the sample code below
<div id="add">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
<div id="edit">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
I can't modify the div container ids i.e exploding since some javascript functions attached to it based on that id to explode address field.
here the problem is if i made any changes to the edit tab, address "exploding" div, it is effecting in add tab address "exploding" since ids are repeated. i have tried jquery detach method to remove the dom elements, but didn't get proper result. Its a web application based on spring boot.
is there any possibility to load jsps dynamically through jquery, i have tried load method as well, but the call is going through controller. I didn't feel it as better option.
Thanks & Regards
krishna K
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">
I have an input field that is nested within another <div> element, and I am trying to use ngMessages on that inside input field, but I can't seem to get it to validate correctly.
<div class="form-group" ng-model="object.idnumber" ng-hide="condition.userObjectsHidden">
<label class="form-control-label col-lg-12">ID Number</label>
<div class="col-lg-12">
<input type="text" name="idnumber" placeholder="111001111"
ng-model="user.idnumber"
ng-pattern="idpattern"
class="form-control input-lg"
required="required"></input>
<div ng-messages="idnumber.$error" ng-if="idnumber.$dirty">
<p ng-message="pattern">You are wrong!</p>
</div>
</div>
</div>
I'm not sure if it matters in terms of functionality where the <div ng-messages...> tag is, but I have also tried having it completely outside of this element with the same results. If I understand Angular and ngMessages correctly, I need to assign ng-messages to a directive--$error in this case--that I get to by dot-walking across name assignments. As far as I know, I have done this with idnumber.$error, although to be fair, I have also tried a more extensive dot-walk by using kiosk-form.uin.$error, where kiosk-form is the name of the entire form.
I have tried both ng-message="pattern" as well as ng-message="required". Also, just for clarity, idpattern is defined in my Javascript file as a regex string. It is defined correctly.
Rename your form as kioskFormand then ng-messages ="kioskForm.idnumber.$error"
I'm doing a list, and the user can filter it with a input text. Now, the field is separated from the select, and I would set the input as an option, like in this image
This is my CODE. Thank you very much!
<div class="row">
<div class="col-md-2">
Search: <input ng-model="query">
</div>
<div class="col-md-10">
<!--Body content-->
<select class="phones">
<option ng-repeat="phone in phones.data | filter:query">
<span>{{phone.name}}</span>
<span>{{phone.age}}</span>
</option>
</select>
</div>
</div>
It is a somewhat complex task, I recommend you use an existing component/library unless your requirements are very, very special.
I can recommend Chosen, which will help you create dropdown menus with filtering through textbox:
https://github.com/harvesthq/chosen
Regarding your requirement from the comments, the need to search not only from the beginning of a word, there is an option in Chosen to achieve that - it's called "search_contains". Refer to Chosen documentation for details:
http://harvesthq.github.io/chosen/options.html
Also see this StackOverflow question regarding "search_contains":
Changing search behavior in jquery plugin Chosen
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