Angular form(s) across multiple tabs, single $pristine/$dirty - javascript

I have read and understood the use of a forms $pristine/$dirty property to detect changes to a form's data.
However, in trying to keep my UI friendly, I have split my various data fields over a number of tabs (I'm using angular-bootstrap). As far as I can tell I have to create a separate
'form' element for each tab and use a controller to test across all the tabs' $pristine states in order to determine the overall pristinity (is that a word?).
i.e.
<tab>
<form name="a">...</form>
</tab>
<tab>
<form name="b">...</form>
</tab>
which means I have to test a.$pristine && b.$pristine to determine the overall pristinity. This becomes laborious when there are many tabs involved.
I have tried
<form name="allForm">
<tab>..</tab>
<tab>..</tab>
<tab>..</tab>
</form>
but this doesnt work. I guess the element breaks the form's 'unity'.
Any ideas on how to get a single $pristine (or $dirty) propoerty for a multi-tabbed tabset ?

It seems to be working for me: http://jsfiddle.net/QqBYR/
A change, compared to yours (unless it was a typo) is that the <form> actually wraps the entire <tabset>:
<form name="theForm">
<tabset>
<tab>
<input ng-model="..." />
</tab>
...
</tabset>
</form>

Related

Vue Get form data as object when taken in as a slot

I am currently creating a wizard tool where the user can create the wizard like so:
<wiz>
<form>
<page>
<label />
<input />
</page>
<page>
<label />
<input />
</page>
</form>
</wiz>
Anything inside the wiz tag is taken in as a slot. And inside the wiz component I slot whats inside the <page> tags into different tabs in the wizard.
I am currently having difficulties when I want to get the form data of the form the user put inside the wizard, I've been looking online but all the solutions I found basically work by you knowing what the labels/inputs of the form will be and building your JSON object with that knowledge.
As for me I have no idea what the contents inside the wizard will actually be as it depends on the user.
I also hope to have the submit button outside the tag if at all possible, though if not It is understandable.
Thank you
You could use something like element.querySelectorAll('input, select, textarea') or document.forms['form_name'].getElementsByTagName('input'); to capture all the form elements. You could then iterate though them to find the values and construct a JSON object (or whatever format you need the data in).

ReactJS: Reusing div element inside render function

Updated My Question based on comments. Not able to make small snippets as its a legacy code with lot of interacting components and I am very new to React to understand all the components.
I have the following GUI:
If you see carefully I have multiple fields with corresponding dropdowns. This combination is represented within a Div in my code under a class within render() function.
The problem is the Div code is repeatedly copy-paste to create a new
field and dropdowns. I don't want to repeat the whole div again and
again and want to replace it with some variable or function which
accepts Field name and DROP_DOWN_TYPE.
I have tried many solutions but it resulted in various errors due to
onchange event.
Repeated div is shown below:
<div className="infoBlock">
<div className="row align-items-center">
<div className="col-6">
<div className="row">
<div className="col-4">
<label className="b_label">Category :</label>
</div>
<div className="col-8">
<Dropdown type="Categories" isMultiple={true} onchange={this.handleDDClick} />
</div>
</div>
</div>
<div className="col-6">
</div>
</div>
</div>
I can't show DropDown code because its a huge file. But its a normal drop down which makes a service call to populate its fields.
Can you give more clarity by making a demo kind of thing on codesandbox.io ?
What I feel is you are repeatedly calling the setState function according to the error.
Either your state is being called repeatedly somewhere , or you need to bind that this.handleDDClick onto that onchange in Dropdown tag. Sometimes it gets triggered without actually any change happening in the dropdown.

loading large array in oi-select takes too much of time in angularjs

I am using oi-select library, i have customized it according to my project need and i have written directive for it. The problem is its taking too much of time say 10secs to load around 3k array data. I want to minimize the time for it. Here I have created plunker for this.
I have directive which loads all factory data and provides it to oi-select, in my code here is html
<small><b>select {{MPhardwaresListDropDown.length}}</b></small>
<div style="padding-top: 7px">
<div title="" class="selected-multiple-items">
{{MPselectedHardwares.length}} selected
</div>
<grid-multi-select id="hardwareId" clean="clean" optionlist="MPhardwaresListDropDown" colval="name"></grid-multi-select>
</div>
HTML code in directive looks like
<div>
<div ng-repeat="optionVal in tempOptionList | orderBy : ['-originalcheck','+label']" prevent-close>
<div ng-if="optionVal.label">
<label class="checkbox" ng-if="!typeFilterOptions || (optionVal.label.toString().toLowerCase().indexOf(typeFilterOptions.toLowerCase()) > -1)">
<input type="checkbox" name="checkbox1" ng-checked="optionVal.check" ng-model="optionVal.check"/>
<span class="checkbox__input"></span>
<span class="checkbox__label" style="color:#A9A9A9;">{{optionVal.label}}</span>
</label>
</div>
<div ng-if="!optionVal.label">
<label class="checkbox" ng-if="!typeFilterOptions || (optionVal.val.toString().toLowerCase().indexOf(typeFilterOptions.toLowerCase()) > -1)">
<input type="checkbox" name="checkbox1" ng-checked="optionVal.check" ng-model="optionVal.check" ng-change="checking(typeFilterOptions)"/>
<span class="checkbox__input"></span>
<span class="checkbox__label" style="color:#A9A9A9;">{{optionVal.val}}</span>
</label>
</div>
</div>
angular code is too big to mention in this question please refer plunker, but this is how it loops
scope.selection = scope.selectionorg;
scope.checkedall=scope.checkedallorg;
scope.OptionList=parentScope[scope.parentListName].sort();
scope.tempOptionList=[];
var i=0;
for(i=0;i<scope.OptionList.length;i++) {
scope.tempOptionList[i] = {val: scope.OptionList[i], check: false, originalcheck: false};
}
if(scope.optionListSelectedList.length>0) {
angular.forEach(scope.optionListSelectedList, function(obj){
angular.forEach(scope.tempOptionList, function(obj1){
if(obj===obj1.val){
obj1.check=true;
obj1.originalcheck=true;
}
});
});
}
else{
scope.checkedall=false;
}
};
I want something like which will load partial data on scroll it loads more data, any help will be appreciated. Thank you so much.
EDIT
Now i have edited my plunker with limitTo in ng-repeat, for that i have written new directive which will trigger addmoreitems function when scroll will reach bottom. updatedPlunker
Now problem is when i am typing and searching something its searching in only available records with respect to limitTo its not searching in all data, say now the limitTo is 50 then search is happening only in 50 records not in 3k records.
Correct way of doing this kind of requirement is to do with pagination, since you are loading data from the server side, you should make your api to support pagination.
It should accept three parameters such as number of items, start, limit and you should initially get the number of items and repeat it until you get the whole result set.
There should be another request to get the total number of items. By doing this you can retrieve all the elements at once loaded in the client side. Until that you should have a loading indicator, or you could load this data when the login process/application starts.
limitTo will not be able to help with the search , because you are limiting the results.
The problem is not the array, the browser can easly handle that, the problem is that you're rendering all the 3k DOM elements, that's really heavy work even for an actual machine, also since there is bindings in each dom element {{}} they're being watching by AngularJs, I got the same problem and solved using Virtual Repeat from AngularJS Material, what this does is it doesn't render the whole 3k DOM elements generated by the ng-repeat, instead it just renders the ones that are visible, also I've found another library if you don't want to use Angular Material, this seems to work the same way: Angular VS-Repeat
You may try the limitTo filter in ng-repeat in angularjs which takes the additional argument to start the iteration.
https://docs.angularjs.org/api/ng/filter/limitTo
On scroll, you can then change that argument based on the number of items pending or left for rendering or the number of items already rendered. This should help you in approach of selective loading of data on scroll.

Angular : template changing depending on javascript value

I am building an angular app, with templates changing depending on with ngscope as seen on the samples below.
<label class="btn btn-default">
<input id="cacher" value="settings" type="radio" data-ng-model="user.status">Settings
</input>
</label>
and here i'm calling my html template userPageSettings
<div id="wrapper" ng-switch="user.status">
<div ng-switch-when="settings">
<user-page-settings></user-page-settings>
</div>
</div>
Trouble is, i'm trying to get access to the templates (and the correct route) through a dropdown in the navbar, which is supposed to do exactly the same thing as my normal menu. But if i simply call the templates from my navbar they will be shown on the current page, therefore at the incorrect route.
In my navbar code i'm doing the following, which is bringing me back to the correct route, but showing me my default template (aka home, not shown here, but called through the same method and has the number 6)
<li role="menuitem">Settings</li>
The number "1" (and the others using 2,3 etc) are hashed in my javascript and put into a variable. I would like to make my templates appear depending on those numbers.
Any ideas how ??
:) Thank you !!

One way binding + dynamic binding in AngularJS

I will start by explaining what we are trying to achieve.
We have just jumped on the Angular bandwagon and are building a prototype with it to see what it is capable of.
Currently there is a load of data (grades in this case) on the server and we display that data using Angular.
The following is the code we use:
<ul class="phones">
<li class="list-group-item" onclick="toggleExpandedView(this, true, 500)" ng-repeat="grade in grades | filter:query | orderBy:orderProp">
<span ng-show="grade.comment"><img src="../Content/images/comment.gif"/></span>
<a class="btn btn-primary editButton" style="float: right; position: absolute; right:10px;" ng-href="#/grades/{{grade.gradeId}}">Edit</a>
<div class="heading1"><a ng-href="{{grade.url}}" target="_blank">{{grade.gradeValue}}</a></div>
<div>Provided by {{grade.assessorFirstname}} {{grade.assessorLastname}} on {{grade.dateModifiedFormatted}} </div>
<div class="expandedGrade" onclick="childDivClick(event)" style="display: none" id="grade-{{grade.gradeId}}">
<label>Attachments</label>{{grade.attachmentCount}}
<br />
<span ng-hide="editing" ng-click="editing = true"><b>{{grade.comment || 'No comments yet'}}</b></span>
<form ng-show="editing" ng-submit="editing = false">
<input type="text" ng-model="grade.comment" placeholder="Comment" ng-required />
<br />
<input id="saveChanges" type="submit" class="btn btn-primary" ng-click="saveChanges(this, grade)" text="Save changes" />
</form>
</div>
</li>
</ul>
As you can see we have a parent ul and for each grade in grades we simply display a li and a div that is hidden and when you click on the li we use jQuery to animate and display the hidden div. In the child div we have a comments field which users can update and click save. On save the current object gets fired back to the server however we are concerned about the fact that Angular has to go through all 2000 grades until it finds the one we are updating (due to two way binding) and this means that everything will be really slow and we cannot afford that.
This is what we want to achieve:
1 We want to bind the data one way so that we can display the list of all grades on the screen and as soon as they are all displayed we want to somehow remove the bindings.
2. When users update the comments for a particular grade we then want to dynamically bind that particular grade so that Angular knows exactly which one it has to update without having to go through the whole collection of 2000+ grades.
I have find a tutorial however I am still unsure how to integrate that into my code.
I have also watched this video and I understand the concept behind it but again, I am struggling to write something that actually works ( we have just started using Angular so I am pretty much a newbie)
Could anyone out there point me in the right direction and provide me with some code samples that would solve the issue we are facing? Any advice and help would be greatly appreciated
You could always use a directive
The logic should go like this
use a service to hold your grades
inject the service into your directive
make a copy and just bind the 'read only view' in your directive
you could watch the service for changes and makes updates as needed
in your directive
as far a lazy loading / updating when needed - use a data service
and call the data service for an update whenever the trigger fires
if your trigger needs to come as a push from some other 'web service' consider a technology
like http://socket.io/
I can put together an example if you would like to see how the services and directives should interact

Categories