Multiple call to onselect from select element with Angular ng-repeat - html

Im using an HTML select element to display an entity's field that has enumerated values in it.
Within the page, I have multiple fields for the entity, therefore multiple select elements.
Im using an Angular ng-repeat to display each field, by creating a select within the ng-repeat on my table row. I want to capture the "onselect" event when an item is selected from any of the drop downs, the trouble is, whenever the user selects a value in one drop down, the event fires for all drop downs on the page.
My html:
<div ng-app>
<div ng:controller="TodoCtrl">
<table>
<tr ng-repeat="prop in customForm">
<td>{{prop.legend}}</td>
<td>
<select ng-name="prop.name" ng-model="entity[prop.name]"
ng-options="val as val for val in prop.enumeratedValues"
onselect="{{fireSelectEvent(prop.name)}}"></select>
</td>
</tr>
<tr><td>Calls Made</td></tr>
<tr ng-repeat="call in callLog">
<td>{{call}}</td>
</tr>
</table>
</div>
</div>
My Controller:
//'use strict';
function TodoCtrl($scope) {
$scope.customForm =
[
{name:"aval", legend: "A Value", enumeratedValues: ["1","2","3"], editable: true},
{name:"bval", legend: "B Value", enumeratedValues: ["4","5","6"], editable: true},
{name:"cval", legend: "C Value", enumeratedValues: ["7","8","9"], editable: true}
];
$scope.entity = {};
$scope.callLog = [];
$scope.fireSelectEvent = function( propName )
{
console.log("Prop=" + propName + " value=" + $scope.entity[propName]);
$scope.callLog.push( propName );
}
}
My fiddle:
http://jsfiddle.net/utgwG/
Good luck. We're all counting on you.

What is the onselect attribute? You're seeing fireSelectEvent fire that many times, because you've bound the onselect attribute using Angular interpolation.
What I'm guessing you want to do is: ng-change="fireSelectEvent(prop.name)"
Your updated fiddle: http://jsfiddle.net/utgwG/2/

Related

Using #input and #output between Angular 2 child components

I have an ng-table which is a child component of my main page. When a row is clicked, it sends the information in that row via onCellClick using an EventEmitter. I'm trying to send this information to another child component. This happens to be a button which is the child of a Bootstrap 4 modal which pops up when a button on the main page is clicked. Just having trouble with the receiving and manipulation of that information.
HTML of child component table:
<ng-table [config]="config"
(tableChanged)="onChangeTable(config)"
(cellClicked)="onCellClick($event)"
[rows]="rows" [columns]="columns">
</ng-table>
HTML for the child component (this appears in the main page's HTML):
<app-datatable (row)="received($event)"></app-datatable>
Typescript for getting and sending the row's data (this.row is the EvenEmitter. data.row is the actual row that's clicked on):
#Output() row: EventEmitter<any> = new EventEmitter<any>();
public onCellClick(data: any): any {
let d = data.row.tDataPoint;
let i = data.row.tICCP;
let s = data.row.tStartDate;
let e = data.row.tEndDate;
let toSend:DataTable = new DataTable(d, i, s, e);
this.row.emit(toSend);
}
HTML for the button that is the child component of the Bootstrap 4 modal:
<button type="submit" class="btn" data-dismiss="modal" (click)="onClick($event)">Delete</button>
Typescript for the button child component:
selector: 'deletebutton'
#Input() receivedRow:DataTable;
onClick(message:DataTable){
this.sender.emit('This is from On Click Deletebutton');
console.log("On Click Deletebutton");
console.log(this.receivedRow);
for (let entry in DPS){
if (DPS[entry].tDataPoint===message.tDataPoint){
DPS.splice(parseInt(entry),1);
}
}
}
HTML of the button child component (this appears in the modal's HTML). This is what should actually be receiving the data from the clicked row as input.
<deletebutton [receivedRow]='row'></deletebutton>
Right now in my onClick method is saying receivedRow is undefined. I feel like what is missing is the coordination between [receivedRow]='row' where I have my deletebutton HTML and the onClick function call in the HTML for that child component. Overall, I just want to click a row, click the button to open the delete Boostrap Modal, and have the correct row be deleted I click the Delete button inside the modal. Let me know if something's not clear or more code is needed.
Is there actually a way to communicate between child components like this using #Input and #Output?
With angular2, your data flow should be :
- down to pass data
- up to send events
So if you really want to go this way, you should have something like that :
I think there's a better way tho :
For your app AND for your user, it'd be best to have a remove button on each line. This way, it avoid the user to be confused clicking on a row and then click on a remove button and within your code you'll be able to do something like that :
src/app.html :
<table class="table">
<tr *ngFor="let row of tableData">
<td *ngFor="let column of row.columns">
{{ column.name }}
</td>
<td (click)="deleteRow(row)"><button>X</button></td>
</tr>
</table>
<button (click)="addRow()">Add a row</button>
src/app.ts (troncated here to the class only) :
#Component({
selector: 'app',
templateUrl: `./src/app.html`,
})
export class App {
private tableData;
private cptRow = 1;
constructor() {
this.tableData = [
{
idRow: `idR${this.cptRow++}`,
columns: [
{idColumn: 'idR1C1', name: 'Column 1-1'},
{idColumn: 'idR1C2', name: 'Column 1-2'},
{idColumn: 'idR1C3', name: 'Column 1-3'}
]
},
{
idRow: `idR${this.cptRow++}`,
columns: [
{idColumn: 'idR2C1', name: 'Column 2-1'},
{idColumn: 'idR2C2', name: 'Column 2-2'},
{idColumn: 'idR2C3', name: 'Column 2-3'}
]
},
{
idRow: `idR${this.cptRow++}`,
columns: [
{idColumn: 'idR3C1', name: 'Column 3-1'},
{idColumn: 'idR3C2', name: 'Column 3-2'},
{idColumn: 'idR3C3', name: 'Column 3-3'}
]
}
];
}
deleteRow(row) {
// we can do this by reference ...
// this.tableData = this.tableData.filter(r => r !== row);
// or by ID
this.tableData = this.tableData.filter(r => r.idRow !== row.idRow);
}
addRow() {
this.tableData.push({
idRow: `idR${this.cptRow}`,
columns: [
{idColumn: `idR${this.cptRow}C1`, name: `Column ${this.cptRow}-1`},
{idColumn: `idR${this.cptRow}C2`, name: `Column ${this.cptRow}-2`},
{idColumn: `idR${this.cptRow}C3`, name: `Column ${this.cptRow}-3`}
]
});
this.cptRow++;
}
}
Here's a working Plunkr : http://plnkr.co/edit/hNhcdraoDNnI2C92TQvr?p=preview
Now, if you really want to use input/output properties, you should look for tutorials because the structure here seems a bit confused. I can help you to understand that (and it's important to understand it with angular2 !) but maybe you should give me a shout on Gitter/Angular instead of detailing Angular2 flow here :)
Somewhat of a work around is to place the Delete button component in the HTML for the table component like this:
<ng-table [config]="config"
(tableChanged)="onChangeTable(config)"
(cellClicked)="onCellClick($event)"
[rows]="rows" [columns]="columns">
</ng-table>
<deletebutton [receivedRow]='toSend'></deletebutton>
And still leave the table's tag in the main page's HTML like I had it:
<app-datatable (row)="received($event)"></app-datatable>
And now the row's data is being sent to that Delete button since it is technically a part of the child component of the main page.
Still not able to communicate between child components like I asked in my question though. But this is something close that works.

AngularJS push multiple rows from module

I have a form where the user choose a supplier from a select box, then a button to choose an item.
When he click the button, a module open and he can search for items. Result came into a table in the module, next to each row there is a + symbol, when he clicks the +, the row come outside the module, and place itself in the table in the main form.
<table>
<tr ng-repeat="row in searchitems">
<td>...</td>
<td>...</td>
<td> <a data-dismiss="modal" ng-click="additemfound(row)"></a> </td>
</tr>
</table>
javascript code:
$scope.additemfound = function(row){
$scope.rowrequest.push(row)};
here i get the row that i chose from the module to the main form and the module close.
I need to push from the module multi row, not only one by one, any solution ?
in the table :
<tr ng-repeat =" row in rowssearchitems"" ng-class="{'selected':
row.selected}" ng-click="addItemFound(row)">
in js
$scope.addItemFound = function(row) {
row.selected ? row.selected = false : row.selected = true;
in html again:
<button ng-click="getallrows();">Get all rows </button>
js:
$scope.getallrows = function(){
var selectedrows = $filter("filter")($scope.rowssearchitems, {
selected : true}, true);
for (var i=0;i<selectedrows.length;i++){
var selectedrowsdata = selectedrows[i];
$scope.rowsrequests.push(selectedrows[i])}
What I did :
I gave a class selected to every row where the user click on the row and the class become selected true then a loop on all rows selected true and push those rows to the main table

Using angularjs, how to perform math operations on textboxes and see result as the values are being typed in?

I have an HTML file with 2 textboxes, one for value and the other for quantity. The result text at the bottom multiplies value with quantity and show the result.
The intention is to show the sum of all the rows of pairs of textboxes on the screen. To that end, I have an "add new" button which keeps adding additional pairs of textboxes.
The first set of textboxes that appear on the HTML, reflect the size of the "numbers" array of objects containing properties "val" and "qty". The same values are bound to the textboxes.
However, only the first set of values are added on screen. As I keep adding new textboxes and entering new values, the value of the result should change accordingly, but it simply doesn't.
HTML Code
<div ng-app="adder" ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-model="number.val"></td>
<td><input type="text" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>pp',[]);
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{sum}}
</div>
</body>
</html>
Javascript
var myapp = angular.module('adder', []);
myapp.controller('addcontrol',function($scope){
$scope.numbers = [
{val:100,
qty:200,
}
];
$scope.add = function()
{
$scope.numbers.push({val:0,qty:0});
};
$scope.deleteNumber = function(val)
{
numbers.splice(val, 1);
};
var result=0;
angular.forEach($scope.numbers, function(num){
result+=(num.val * num.qty);
});
$scope.sum = result;
});
What am I doing wrong here?
In your code, the calculation of the sum would only be executed once.
You need to add a watch of the scope or bind a function to ng-change event in order to keep the sum updated while you change the numbers.
For example, you can do:
<div ng-app="adder" ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-change="update()" ng-model="number.val"></td>
<td><input type="text" ng-change="update()" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>pp',[]);
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{sum}}
</div>
And:
var myapp = angular.module('adder', []);
myapp.controller('addcontrol', function($scope) {
$scope.numbers = [{
val: 100,
qty: 200,
}
];
$scope.add = function() {
$scope.numbers.push({
val: 0,
qty: 0
});
};
$scope.deleteNumber = function(val) {
numbers.splice(val, 1);
$scope.update();
};
$scope.update = function() {
var result = 0;
angular.forEach($scope.numbers, function(num) {
result += (num.val * num.qty);
});
$scope.sum = result;
};
});
I know this a little bit besides the question but you can do arbitrary arithmetic operations inside a single input field:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="">
<input ng-model="expression"/>
<p>{{$eval(expression)}}</p>
</body>
Based on Pylinux's answer: it may seem obvious, however here it is. If you want to add 2 expressions, use the following:
{{$eval(expression1)+ $eval(expression2) }}
The code in your controller is only activated once (when the view is rendered). Therefore, your sum is only computed once, before you even get a chance to add any rows. What you need to do is put your calculation into a function so that it can be called repeatedly as needed.
Tong's answer is basically correct, but I think this is a nicer way to do it:
<div ng-controller="addcontrol">
<table>
<tr>
<th>Value</th><th>Quantity</th>
</tr>
<tr ng-repeat="number in numbers">
<td><input type="text" ng-model="number.val"></td>
<td><input type="text" ng-model="number.qty"></td>
<td><input type="button" ng-click="deleteNumber($index)" value= "Delete"></td>
</tr>
</table>
<input type="button" ng-click="add()" value="Add new">Result : {{total()}}
</div>
and
var app = angular.module('app', [])
.controller('addcontrol', function($scope) {
$scope.numbers = [{
val: 100,
qty: 200,
}];
$scope.add = function() {
$scope.numbers.push({
val: 0,
qty: 0
});
};
$scope.deleteNumber = function(val) {
$scope.numbers.splice(val, 1);
};
$scope.total = function(){
var total = 0;
angular.forEach($scope.numbers, function(num) {
total += (num.val * num.qty);
});
return total;
}
})
Define a total function that loops through the array and returns the appropriate sum. Then you can bind that function to the result field in the view. The benefit of doing it this way is that you don't have to remember to call update() everywhere that might cause the total to change (like ng-change on the textboxes, and in the deleteNumber function). The total just updates automatically.
Here's a demo.
Php
Create a database named as students(using cmd)
Create a table named as tbl_students_info with column:
id, data type is int with size of 11, auto increment and set as primary key
Firstname, data type is varchar with size of 30
Middlename, data type is varchar with size of 30
Lastname, data type is varchar with size of 30
Contact, data type is int with size of 11
House_address, data type is int with size of 50
Create a webpage that contains 5 textbox and 1 button. 1st textbox is for firstname, 2nd textbox is for middlename, 3rd textbox is for lastname, 4th textbox is for contact, last textbox is for house_address and button for saving the input data in those texboxes to database
Angular
Create a calculator that computes the sum of 2 numbers, product of 2 numbers, difference of 2 numbers and quotient of 2 numbers. The web page must contain 2 textbox and 4 buttons for the operations.
Create a wepage that computes the area of a triangle. Must have 2 textbox and a button for calculate area.
Create a website that calculate the age of the user. Must have a textbox and a button, textbox is for input birth year and button for compute age. Note: no need for exact months.
Help TT

Dropdownlist binding to an object not returning selected object

I am binding an object to a dropdownlist using Knockout 2.2.1. The binding is working for putting the correct items in the list but when I try to get the OBJECT selected it is not working. I have a JSFiddle showing this problem; http://jsfiddle.net/CTBSTerry/g4Gex/
Html
<div style="margin-bottom: 15px;">
Your Choices:
<select data-bind="options: choicelists[0].options, optionsText: 'otext', optionsValue: 'oprice', value: selOpt1, optionsCaption: 'Choose...'"></select>
</div>
<div data-bind="visible: selOpt1" style="margin-bottom: 15px;"> <!-- Appears when you select something -->
You have chosen<br>
From Object:
<span data-bind="text: selOpt1() ? selOpt1().otext : 'unknown'"></span>
<br>From Value:
<span data-bind="text: selOpt1() ? selOpt1() : 'unknown'"></span>
</div>
JavaScript:
var mychoice = function (txt, price) {
this.otext = txt;
this.oprice = price;
}
var viewModel = {
prodphoto: "",
prodname: "",
prodDesc: "",
baseprice: "",
choicelists: [
{ 'listlabel': 'Size List',
'options': ko.observableArray([
new mychoice('Small', 'Small|$|0.00'),
new mychoice('Medium', 'Medium|$|0.00'),
new mychoice('Large', 'Large|$|0.00'),
new mychoice('X Large + 2.00', 'X Large|$|2.00'),
])
}],
textlists: [],
selOpt1: ko.observable()
}
ko.applyBindings(viewModel);
When you click the dropdown to make a choice I have 2 spans that attempt to show the selected value which I want as the object selected not just the specific value field. The object notation returns nothing but does not error. The second span shows the selected value but since it is not the selected object I would have to iterate through the object to get the related object. The Knockout documentation shows a very similar sample but I need a bit more complex view model. Can someone help me and point out why this is not working?
Thanks,
Terry
If you remove optionsValue from your binding, then Knockout will use the actual object rather than a property on it.
So, you would want to remove optionsValue: 'oprice' from the binding, then selOpt1 will be populated with the actual object.
Sample: http://jsfiddle.net/rniemeyer/g4Gex/1/

How to add button or images to dojo grid

I have a dojo grid with a json datastore (mysql resultset converted into json format). Currently my grid show 5 columns as shown below in the figure:
I have column named 'Action'. The rows under this 'Action' column should contain buttons or images(edit icon, delete icon) with hyperlinks such as edit.php?id=1 for edit, or delete.php?id=1 for delete.
Here is my dojo grid code:
<span dojoType="dojo.data.ItemFileReadStore" data-dojo-id="studentsStore" url="http://localhost/newsmis/public/studentManagement/student/fetchdata/data/1"></span>
<table dojoType="dojox.grid.DataGrid" id="studentsGrid" data-dojo-id="studentsGrid" columnReordering="true" sortFields="['idstudents','first_name','middle_name','last_name']" store="studentsStore" clientSort="true" selectionMode="single" rowHeight="25" noDataMessage="<span class='dojoxGridNoData'>No students found</span>">
<thead>
<tr>
<th field="idstudents" width="20%">Student ID</th>
<th field="first_name" width="20%">First Name</th>
<th field="middle_name" width="20%">Middle Name</th>
<th field="last_name" width="20%">Last Name</th>
<th field="action" width="20%">Action</th>
</tr>
</thead>
</table>
My json data format is
{"identifier":"idstudents","items":[{"idstudents":"11","first_name":"Pradip","middle_name":"Maan","last_name":"Chitrakar"}]}
How can i do it? Please suggest me some ideas
The one way I know is, that defining formatting method for that column in grid structure. So instead of defining the structure of the grid declaratively, define in JavaScript object like below
var structure = [
{
name: "First Name",
field: "first_name"
},
{
name: "Action",
field: "_item",
formatter: function(item){
var btn = new dijit.form.Button({
label: "Edit"
});
return btn;
}
}
]
and set this structure to the grid
<table dojoType="dojox.grid.DataGrid" id="studentsGrid" data-dojo-id="studentsGrid" columnReordering="true" sortFields="['idstudents','first_name','middle_name','last_name']" store="studentsStore" clientSort="true" selectionMode="single" rowHeight="25" noDataMessage="<span class='dojoxGridNoData'>No students found</span>" structure=structure >
Here is the working example,
Image in dojo Grid
As documentation of dojox.grid.DataGrid stays:
Beginning with Dojo 1.7, you should use dgrid or gridx, next-generation grid components that take full advantage of modern browsers and object stores.
piece of code example:
columns: [
{
field: "id",
label: "ID"
},
{
field: "name",
label: "Name"
},
{
field: "options",
label: "Options",
renderCell: function (obj) {
var cellContent = domConstruct.create("div",{});
var btn = new Button({
label: "Cell " + obj.id,
name: "idBtn"
})
btn.placeAt(cellContent);
on(btn, "click", function (evt) {
console.log(obj);
});
return cellContent;
}
}
]
This is JSfiddle example how to do it in dgrid by using function renderCell in column properties of dgrid.
renderCell(object, value, node, options) - An optional function that will be called to render the value into the target cell. object refers to the record from the grid’s store for the row, and value refers to the specific value for the current cell (which may have been modified by the column definition’s get function). node refers to the table cell that will be placed in the grid if nothing is returned by renderCell; if renderCell returns a node, that returned node will be placed in the grid instead. (Note: if formatter is specified, renderCell is ignored.)
If you don't want a button, but only an image icon, you can return a span-element from the formatter function like this:
formatter: function(value) {
var myValueClass = "dijitNoValue";
...
myValueClass = "ValueClass1";
...
return "<span class='dijitReset dijitInline dijitIcon " + myValueClass + "'></span>";
}
An css class has to be defined like
.ValueClass1 {
background-image: url('val_image1.png');
background-repeat: no-repeat;
width: 18px;
height: 18px;
text-align: center;
background-position: 1px;
}