ng directives for adding new row once using angular js - angularjs-directive

I have table of textboxes. When i try to add the text ion last row I should get new blank row of textboxes added on new row. Currently ng-Blur is there. And I am getting new blank row added on lost focus. But i want it on 1st key press.
If I use ng-keypress or ng-change then on entering each new character new row is added which is not right. Or can I restrict the event to once.
Please let me know what can be done?
following is my HTML code
<div class="col-md-5">
<input placeholder="New Key" ng-model="propertyKey" ng-blur="addNewRow()" class="form-control" type="text" id="key">
</div>

One approach would be to pass the current row index into your ng-keypress handler and only add a new row if the index is exactly one less than the row count.
So your component/directive template would look something like this:
<div ng-repeat="row in $ctrl.rows">
<input placeholder="{{ row.id }}" ng-keypress="$ctrl.handleKeypress($index)" />
</div>
where you pass the $index of the ng-repeat instance to your keypress handler, and that handler would look something like this (assuming this.rows is your data array):
this.handleKeypress = (rowIndex) => {
if (rowIndex === this.rows.length - 1) {
this.rows.push({ id: `row${rowIndex+1}` });
}
};
So once you've added one extra row beyond the current one you're in, no more will be added.
Here's a plunk showing this approach:
http://plnkr.co/edit/4HbYg4S7M67Vpib6dI0E?p=preview

Related

Scoping Issue in Table when trying to access a specific row in a dilaog box (Vue.js, Element-ui)

I have created a table using el-table (Element-ui) in Vue.js. I want to access a specific row in the table when clicked on a button in that row, but the catch here is that after clicking on the button, a dialog box should open up and then access that specific row. When I try to access the row outside of the dialog box using scope.row, it works perfectly fine but it does not work properly when accessed inside teh dialog box, instead it runs in a loop till the end of the table.
Please find the code below:
<el-table-column prop="count"
label="Total">
<template slot-scope="scope">
<!-- {{fetchData(scope.row)}} When scope.row is accessed here, it works perfectly-->
<el-button type="text" #click="dialogVisible = true">{{scope.row.count}}</el-button>
<el-dialog
:visible.sync="dialogVisible"
:before-close="handleClose">
<!--I want to access the speicfic row clicked here, but it ends up looping through the table and doesnt send that specific row only. -->
{{fetchData(scope.row)}}
</el-dialog>
</template>
</el-table-column>
Can someone please suggest some solution to this issue in the above code? I am stuck on this for while. Would appreciate it.
Thank you.
This is a table... So fetchData will be called for each row as your code sits now.
But if you attach fetchData on the button instead, it will work. But then you would have to add a variable to the mix, or use a computed property. Anyways, I don't like calling functions in template, handle that logic in script or using computed properties. So here's what I'd do:
data() {
return {
chosenRow: null
}
},
methods: {
fetchData(row) {
this.chosenRow = row;
}
}
Template:
<template slot-scope="scope">
<el-button type="text" #click="fetchData(scope.row); dialogVisible = true">
{{ scope.row.follower_count }}
</el-button>
<el-dialog :visible.sync="dialogVisible">
{{ chosenRow }}
</el-dialog>
</template>
or just assign the row in template...
#click="chosenRow = scope.row; dialogVisible = true"

How do you add a value to datepicker from an Angular Factory?

i have an Angular Factory that gets a single date from the backend of my spring application, and i wanted to add it to an Input so the calendar input is always set with the date obtained from the backend, without the possibility for the user to change it. How could i achieve this? Should i put it on my controller or directly on the button? This is my code:
Factory(concatenated with other .factory):
.factory('DataInizioGeneraCalendario', function ($resource) {
return $resource('rest/anagrafica/dataInizioGeneraCalendario', {
get: {
method: 'GET'
}
});
Controller Function:
$scope.generaCalendario = function () {
$scope.modificaCalendarioDiv = true;
$scope.successMessage = false;
$("#idModificaCalendarioDiv").hide();
$scope.element = new Calendario();
autoScroll('generaCalendario');
$("#idErrorTemplate").hide();
$('#data').attr('disabled', false);
$("#idGeneraCalendarioDiv").show();
};
Input :
<div class="col-xs-12 col-md-2" >
<label for="dataInizio" class="row col-xs-12 control-label" style="text-align: left">da Data</label>
<input class="datepicker form-control" placeholder="gg/mm/aaaa" required type="text" id="data" ng-disabled="true" />
</div>
Edit : forgot to add, the controller function is called by the button that displays the input for the calendar.
Because your factory's GET request will return the date value asynchronously, it's better to have a $scope.date in your controller that will hold the date value that is returned from the server. Also, depending on the format in which you store dates on the backend, you might need to transform the value that is returned from the backend into the string format, so it would be properly consumed by the <input type="date"> as per Angular docs.
In your code, you need to bind the input element to this value, like this: <input ng-model="date">.
What it will do is bind this input to the data model, so that every time when user edits the input the $scope.date would be updated too.
If you do not want users to be able to edit this date, then you need to:
Keep the input field disabled <input disabled> (no need to use ng-disabled here, because you want to keep it always disabled). And also remove this line: $('#data').attr('disabled', false); in your function.
You the one-way binding, instead of two0way binding, like this: <input disabled ng-value="date">
Here is the working DEMO that shows two inputs: one that is editable and another that is not.

Inputfield unfocus after typing 1 character

I can't seem to write down a full word without being unfocused after each character I type in the inputfield. Trying to understand why that is.
AngularJS
var module = angular.module("myModule", []);
module.controller("myController", function($scope) {
$scope.prop = {};
});
HTML
<div ng-app="myModule">
<div ng-controller="myController">
<button ng-show="!prop.dropdownType"
ng-click="prop.dropdownType = ['']">Init</button>
<div ng-hide="!prop.dropdownType" ng-repeat="(key, value) in prop.dropdownType">
<input type="text" ng-model="prop.dropdownType[key]">
</div>
<button ng-hide="!prop.dropdownType"
ng-click="prop.dropdownType.push('')" >Add options</button>
</div>
</div>
EDIT: created a quick code where you can see what i mean. Just run the code, initialize the inputfield and try to type a word: https://jsfiddle.net/wk173q0a/
I was able to fix your code by making the following change:
<div ng-hide="!prop.dropdownType">
<input ng-repeat="type in prop.dropdownType track by $index" type="text" ng-model="type">
</div>
The problem is that you are updating the key for the values in which you are iterating over. This is kicking off a digest cycle and you are losing focus. Also, the add button did not work because you were adding identical objects with no tracking.
Lastly, you will want to iterate over an array of objects to be able to maintain the reference in ng-model. Otherwise, all the changes will be lost once you add a new value to your array.
This is a great read on understanding the digest cycle:
https://www.thinkful.com/projects/understanding-the-digest-cycle-528/
This is happening because you are updating the list/object that controls your ng-repeat.
prop.dropdownType may start as [''], but as soon as you type into your input, you are updating the prop.dropdownType object. AngularJS sees that you have changed the prop.dropdownType and it refreshes the dom with the new input. If you typed the character A, the prop.dropdownType will now have a key of A (and a value of null?) and the input you see is now a different object.
If you change your ng-model to be a separate array or some other property, this issue should go away.
This is happening because of ng-repeat in tag. So, in this case try below 2 methods to solve the input element focus issue.
1) Use track by $index
<div ng-hide="!prop.dropdownType" ng-repeat="(key, value) in prop.dropdownType track by $index">
<input type="text" ng-model="prop.dropdownType[$index]">
</div>
2) Wrap your strings into objects. E.g. prop.dropdownType = [{value: 'string1'}, {value: 'string2'}, ...]:
<div ng-hide="!prop.dropdownType" ng-repeat="(key, value) in prop.dropdownType">
<input type="text" ng-model="prop.dropdownType[$index].value">
</div>

ANGULARJS: Function I have in ng-checked directive runs infinitely

Trying to do something I thought is pretty simple but it's turning out to be pretty annoying. I'm just trying to have a function that runs when you click on a checkbox using the ng-checked directive.
This is the HTML:
<div class="form-group">
<label class="col-sm-2 control-label">Make Payment Optional</label>
<div class="col-sm-4 center-checkbox">
<input type="checkbox"
class="center-checkbox"
ng-model="formData.optionalPayment"
ng-checked="optionalPaymentCheckbox();"
validate-servererror="featured"/>
</div>
</div>
And this is the Angular:
if($scope.formData.optionalPayment === undefined) {
$scope.formData.optionalPayment = TournamentConst.PAYMENT.OPTIONAL;
}
(This check is just for when I load the page for the first time.)
$scope.optionalPaymentCheckbox = function () {
if($scope.formData.optionalPayment === TournamentConst.PAYMENT.OPTIONAL) {
$scope.formData.optionalPayment = TournamentConst.PAYMENT.MANDATORY;
} else {
$scope.formData.optionalPayment = TournamentConst.PAYMENT.OPTIONAL;
}
};
When I load the page, this ng-checked function runs infinitely. Is there something about the ng-checked directive I don't know, or some minor detail or forgot? Thanks in advance.
You are misunderstanding the intention of ng-checked. What you think it does is "execute this expression when the checkbox is checked" - an event handler directive.
What it actually does is set the checked property based on the expression. This means it sets up a watch on the expression and evaluates it every digest. If the value changes, it sets or unsets the checked property accordingly.
In fact, the documentation for ng-checked says this:
Note that this directive should not be used together with ngModel, as this can lead to unexpected behavior.
As #JB Nizet correctly pointed out, you can achieve the desired effect in your particular case by using ng-true-value and ng-false-value and removing ng-checked altogether.
So your HTML becomes:
<div class="form-group">
<label class="col-sm-2 control-label">Make Payment Optional</label>
<div class="col-sm-4 center-checkbox">
<input type="checkbox"
class="center-checkbox"
ng-model="formData.optionalPayment"
ng-true-value="TournamentConst.PAYMENT.MANDATORY"
ng-false-value="TournamentConst.PAYMENT.OPTIONAL"
validate-servererror="featured"/>
</div>
</div>
Then, in your controller, populate your TournamentConst object in the scope, so the template can see it:
$scope.TournamentConst = TournamentConst;
(or you can just populate the bits you need)
Finally, get rid of the whole $scope.optionalPaymentCheckbox function. You will still need the code to set the default value, though.
One last thing: It is confusing that the property is called optionalPayment, when it is really more like paymentType, but that is not related to the current problem.

AngularJS, checkboxes, and generating dynamic html

I am wanting to generate a table dynamically using Angular JS, based on what is checked on some checkboxes. The problem is that there are a few fields, we will call them relation/column, that I want to display ALWAYS, and the remaining fields only if their box is checked. The relation is searched for via a search box (relations can have multiple columns), and I want to display only the properties of that relation that are relevant to a user.
So
Update Time [X]
Update Status [ ]
Time Zone [ ]
Would display some html along the lines of
<table>
<tr>
<th> Relation </th>
<th> Column </th>
<th> Update Time </th>
</tr>
<tr ng-repeat= "result in results">
<td> {{result.relation}} </td>
<td> {{result.column}} </td>
<td> {{result.update_time}}</td>
</tr>
If no boxes were checked, only the relation and column fields would be populated. The documentation for Angular JS is taking me all over the place, so would anyone have an idea on how to do this?
edit : controller isn't working quite yet, I still need to filter the search results, but basically it goes
$scope.search = function(){
//validate form input
//create url with the input recieved
$http.get(url).success(function(data){
$scope.results = angular.fromJson(data);
});
}
I use mojolicious backend to grab the data I want. Again, the problem isn't that I can't get any data, or that I can't filter the results based on the relation. I want to be able to search based on relation, and only display the attributes of that relation that I want to, based on what is checked. THAT part, I can't figure out.
edit again : the firewall where I'm at prevents me from writing comments/upvoting. You shall be rewarded for your help when I get home tonight. Thank you thank you!
I think the best way to do this would be using ng-show expressions tied to a variable in the model.
For example.
<input type="checkbox" ng-model="updateTime">
makes a checkbox and ties the result to $scope.updateTime. You can then use this variable later on via the ng-show directive like so...
<th ng-show="updateTime"> Update Time </th>
...
<td ng-show="updateTime"> {{result.update_time}}</td>
this means that these elements will only show when updateTime is set to true (i.e the checkbox is checked.)
You can see an example here, I've only implemented the one field but it should be possible to extend it pretty easily!
http://plnkr.co/edit/W6Ht6dnGw4fBplI83fB1?p=preview
I would suggest using a custom filter with the checkbox scope variables passed in. Something like this:
html
<input type="checkbox" ng-model="checkbox1" />
<input type="checkbox" ng-model="checkbox2" />
<input type="checkbox" ng-model="checkbox3" />
... ng-repeat= "result in results|checkboxFilter:{checkbox1,checkbox2,checkbox3}"
filter.js
.filter('checkboxFilter', function() {
return function (results, checkbox1, checkbox2, checkbox3) {
var filtered_objects = angular.copy(results);
for (var i = 0, len = filtered_objects.length; i < len; i++) {
**modify your filtered_objects based on your checkboxes**
if (checkbox1) ...
if (checkbox2) ...
if (checkbox3) ...
}
return filtered_objects;
}
});
Maybe something like that.