AngularJS grouping values and adding them together in ng-repeat - javascript

I'm trying to create a total sum of a group in AngularJS. I'm using http to get the results into a html table :
$http({method: 'GET', url: urlpurchasing}).success(function(data) {
$scope.purchasing = data;
})
Which gives the below result :
I want to make a new column called "total stock" and add all of the "Quantity sold" for each group, so for all which have a Desc of the same value i want there "quantity sold" to be added up. For example, the 3 purple rows at the bottom would have "607" in there "total sold" column.
I tried to loop through the data with an angular for-each and add each one up but this involves creating a second array and any kind of filter or change in the main table changes the indexes and it mixes up. Appreciate any assistance.
edit
This is what i have so far (but the totals are incrementing each time :
$http({method: 'GET', url: urlpurchasing}).success(function(data) {
var t = 0;
angular.forEach(data, function(obj){
if($scope.code == obj.GroupCode){
}
else
{
$scope.code = obj.GroupCode;
t = 0;
}
t = (t + parseInt(obj.QuantitySold));
obj.total = t;
});
$scope.purchasing = data;
})
Here is the PHP :
<?php
require_once('sqlconnect.php');
$sqlQuery = "select StockCode,Description,QuantityInStock,QuantitySold,NetAmountSold,GroupCode,color from purchasing order by Description desc";
$result = $unity_connection->query($sqlQuery);
$json1 = array();
while($rows = mysqli_fetch_assoc($result)){
$json1[] = $rows;
}
echo json_encode($json1);
?>

I don't use MySQL, but standard SQL should do the trick here:
SELECT
purchasing.stockcode,
purchasing.description,
purchasing.quantityinstock,
purchasing.quantitysold,
purchasing.netamountsold,
purchasing.groupcode,
purchasing.color,
desc_summary.totalstock
FROM
purchasing join (select description, sum(quantitysold) as TotalStock from purchasing group by descrption) desc_summary on purchasing.description = desc_summary.description
ORDER BY purchasing.description DESC

You can achieve this by multiple ways, either to create extra variable for total in your controller scope or directly in your data\json as well., or by extending $scope.purchansing
OR, if you don't want any further $scope property, then you can invoke a function at run time to calculate the total for each group..
See this fiddle in which I tried with run time function which checks for group total per group.
Updated fiddle to extend your scope data in controller.

Related

Get names and links values when looping HTML elements with Javascript

I am making a web app for a Spreadsheet for a sidebar.
Trying to handle an event listener that implements these conditions:
when checking checkboxes (which have correspondent names and Calendar links for that names)
and picking 2 dates
and then clicking the button
After it's all done a function is called from backend which gets events for that names and records them to a sheet.
I can't get the values for names and calendars in a loop. And not sure what's the good way to put them. I tried to handle it in different ways - no luck.
I eventually narrowed all issues to these 2 parts:
1) how to load data to a sidebar in a best way.
2) how to loop through that data after user interacted with these elements and to get values (depends on the part 1).
I would really appreciate if someone help me a bit more on it (some rather simple solutions).
Here's the variant with scriptlets for using GAS in an html file:
<? for (var i = 0; i < loopNamesForSidebar().names.length; i++) { ?>
<label>
<input type="checkbox" class="filled-in check" checked="checked" />
<span>
<div class="collection">
<a href=" <?= loopNamesForSidebar().calendars[i] ?>" class="collection-item" >
<?= loopNamesForSidebar().names[i] ?>
</a>
</div>
</span>
<? } ?>
</label>
loopNamesForSidebar() is a backend function which loops names and calendars that go to the sidebar. Every time I open the sidebar this data refreshes. I don't have it used in my front-end part.
Here's a Javascript code in an html file:
//import jobs from calendars to sheet
function importJobs() {
//getting all checkboxes
var allCheckboxes = document.getElementsByClassName("check")
//getting inputs of start and end dates
var startDate = document.getElementById("startDate").value
var endDate = document.getElementById("endDate").value
var chosenNames = []
var calendars = []
//looping all checkboxes
for (var i = 0; i < allCheckboxes.length; i++) {
//getting value of each checkbox
var checkbox = allCheckboxes[i].checked;
//if checkbox is checked
if (checkbox == true) {
//getting correspondant employee name
var name = loopNamesForSidebar().names[i]
//and push it to an array
chosenNames.push(name)
//getting correspondant employee calendar
var cal = loopNamesForSidebar().calendars[i]
calendars.push(cal)
} else {
continue;
}
};
//push names and cals to object
var employees = {
names: chosenNames,
cals: calendars
}
//call function to get calendar events
google.script.run.getEvents(employees, startDate, endDate)
};
Per Best Practices, you should load any API / ___ Service call output asynchronously. I would only use template evaluation for trivially computed / retrieved data, e.g. from PropertiesService, CacheService, static definitions, or simple lookups based on input parameters (i.e. querystring / payload data for doGet and doPost trigger functions). If it takes longer than a quarter second on average, it's too slow for synchronous usage.
so:
function templateOK(param) {
const val = PropertiesService.getScriptProperties().getProperty(param);
return val ? JSON.parse(val) : [
"name 1", "name 2", "name 3"
];
}
function shouldRunAsync(param) {
const sheet = param ? SpreadsheetApp.getActive().getSheetByName(param) : null;
return sheet ? sheet.getDataRange().getValues() : [];
}
Assuming you've set up the other parts of your GS and HTML files appropriately, one of the .html's <script> tags may look something like this:
$(document).ready(() => loadServerData()); // jQuery
function loadServerData() {
const TASK = google.script.run.withSuccessHandler(useNames); // has implicit failure handler of `console`
// Schedule this to be run every so often
const intervalMS = 10 * 60 * 1000; // 10 minutes
setInterval(sheetName => TASK.shouldRunAsync(sheetName), intervalMS, "Names");
// Invoke promptly too.
TASK.shouldRunAsync("Names");
console.log(new Date(), "Set schedule & invoked server function");
}
function useNames(serverValue, userObject) {
console.log(new Date(), "Got Value from server", serverValue);
// use the return value to do stuff, e.g.
const cbDiv = $("id of div containing checkboxes"); // jQuery
/** could add code here to read existing checkbox data, and
use that to maintain checked/unchecked state throughout loads */
cbDiv.innerHTML = serverValue.map((name, idx) => `<p id="${name}">${idx + 1}: ${name}</p>`).join("");
}
As always, make sure you are intimately familiar with the serializable data types and the Client-Server communication model: https://developers.google.com/apps-script/guides/html/communication
Other refs
Element#innerHTML
Array#map
setInterval
Arrow functions
Template literals

Deconstructing a JSON object

A JSON encoded array is passed from PHP to an HTML document. It is not at all clear how to deconstruct that array into javascript-usable pieces. For example, consider the following HTML:
<div id="options">{"foo":[{"id":1},{"id":3}], "bar":[{"id":2},{"id":4}]}</div>
The only a priori known element of this array is that the key id exists. The indices, I know, can be found with
var data = JSON.parse($("#options").text());
$.each(data, function(index) {
// index will be foo & bar
});
The use case is to use the index and id to add an attribute to elements in a document. I have not yet stumbled upon the technique to return the ids associated with each index. How best can that be done?
Edit - a clarification of the use case - the long story
I want to re-enable some options on a form based on properties of an entity (in a Symfony application). Disabled options cannot be modified, but are also not not persisted - their values are set to null. I've built a service to determine the option elements that are disabled and send those elements to the form document as a JSON object. I'm assuming for now that the specific options are not known until the form is created. In the example above, foo & bar represent possible options, and the ids correspond to the option. For example, a Household entity might have Reason options selected but disabled of "Low wages" (id = 3). This would show up in as ...id="options">{"reasons":[{"id":3}]}<.... I would the use this information to remove the disabled="disabled" attribute from the set of checkboxes for the Reason, id=3 (i.e., id="household_reasons_3") field. I hope this makes sense.
Edit #2, by request - the PHP code creating the object.
The result of getMetatData() appears in the document at #options. From the above edit, the Household entity is $object.
public function getMetaData($object) {
$data = array();
$className = get_class($object);
$metaData = $this->em->getClassMetadata($className);
foreach ($metaData->associationMappings as $field => $mapping) {
if (8 === $mapping['type']) {
$data[$field] = $this->extractOptions($object, $field);
}
}
return json_encode($data);
}
private function extractOptions($object, $field) {
$data = [];
$method = 'get' . ucfirst($field);
$itemName = substr($field, 0, -1);
$getter = 'get' . ucfirst($itemName);
$entity = $object->$method();
foreach ($entity as $item) {
if (method_exists($item, 'getEnabled') && false === $item->getEnabled()) {
$data[] = ['id' => $item->getId()];
}
}
return $data;
}
Long before the infinite monkey limit was reached I stumbled on a method to create the results I was looking for. My thanks go out to all who pushed for clarifications. So, for the object
{"foo":[{"id":1},{"id":3}], "bar":[{"id":2},{"id":4}]}
the script
var data = JSON.parse($("#options").text());
var i = 0
var output = [];
$.each(data, function(index, item) {
$.each(item, function(k, v) {
output[i] = "household_" + index + "_" + v.id;
i++;
});
});
output;
produces this:
["household_foo_1", "household_foo_3", "household_bar_2", "household_bar_4"]
I get the strings I need; I can take it from here.

How to build an Ajax search bar with multiple keywords?

I tried to build an ajax search bar. It works fine with a single keyword but I can't manage to make it work with 2 keywords...
I was thinking about parsing the data in the input field but my knowledge is limited and I didn't manage to find the solution.
Any ideas?
In my main.js I get the data from the input like this:
var kwVal = $(this).val();
if (kwVal.length < 3){
$(".clothes-container").html("");
}
else {
$.ajax({
"url": "ajax/getclothes.php",
"type": "GET",
"data": {
"kw": kwVal
}
})
And this is my sql request
$sql = "SELECT title, description, picture
FROM outfit
WHERE type LIKE :keyword OR
color LIKE :keyword OR
brand LIKE :keyword OR
material LIKE :keyword";
Thanks a lot.
Something like this? Of course, all the SQL literals and strings must be properly escaped (especially the $keyword).
// keywords extracted from user's input
$keywords = array('blue', 'jeans');
// columns, that You want to match against
$columns = array('type', 'color', 'brand', 'material');
// we build the condition for each keyword
$word_conditions = array();
foreach ($keywords as $keyword) {
$conditions = array();
foreach ($columns as $column)
$conditions[] = $column.' LIKE \'%'.$keyword.'%\'';
$word_conditions[] = '('.implode(' OR ', $conditions).')';
}
// we build the query, that requires every item to have all the keywords
$query = 'SELECT * FROM ... WHERE '.implode(' AND ', $word_conditions);
Suppose your keywords are saperated by 'Space' like "ABC DEF GEH".
than on server you can do is,
$keywords = explode(" ", $_POST['data']); //Make it array;
$string = implode(",", $keywords);
$sql = "SELECT title, description, picture
FROM outfit
WHERE type in (".$string.") OR
color in (".$string.") OR
brand in (".$string.") OR
material in (".$string.")";

Laravel: upload multiple rows created from arrays

I'm building an application with Laravel which communicates with an OpenCPU server to perform some calculations. The OpenCPU server returns data in JSON format, which I then process to pull out the relevant information. This data returns a sku, retailer, date and sales. These are then posted to a controller using AJAX. Within this controller I then want to upload this data into the database by creating a new array of data to upload in one go. Each row should have a sku, retailer, date and sales. The date field in the database is called date, but called obs in the code.
OpenCPU returns JSON which is the parsed to a Javascript object using
var data = JSON.parse(output);
After logging to the Javascript console I get an array of the correct length, with the sales numbers.
The data is then sent to a Laravel controller via AJAX
$('#save').click(function(){
var id = $('#filter option:selected').text();
var json = $.ajax({
url: 'sales/' + id + '/update',
type: 'POST',
data: {
'sku': $('#sku').text(),
'retailer': $('#retailer').text(),
'obs': data.OBS,
'sales': data.Sales,
},
async: false
}).responseText;
var message = JSON.parse(json);
$('.flash').html(message).fadeIn(300).delay(2500).fadeOut(300);
});
In Laravel I then try to store the data in a MySQL database using the following
$sku = Input::get('sku');
$retailer = Input::get('retailer');
$obs = Input::get('obs');
$sales = Input::get('sales');
foreach($obs as $key => $n ){
$arrayData[] = array(
'sku' => $sku,
'retailer' => $retailer,
'date' => $obs[$key]
'sales' => $sales[$key]
);
}
Chart::create($arrayData);
However the above code doesn't appear to work. The following code will create the correct number of rows in the database with the sku and retailer populated, but the sales figure is just the loop number, rather than the number of sales
$sku = Input::get('sku');
$retailer = Input::get('retailer');
$dates = Input::get('obs');
$sales= Input::get('sales');
foreach(range(1, count($dates)) as $key){
DB::table('charts')->insert(
[
'sku' => $sku,
'retailer' => $retailer,
'date' => DateTime($obs[$key]),
'sales' => $sales[$key]
]
);
}
Given that the sku and retailer are a single input and repeated, I expect it's either an issue with passing the array to Laravel or the way in which I'm trying to access the elements in the 'obs' and 'sales' array
It looks like you have the right steps, get the inputs:
$sku = Input::get('sku');
$retailer = Input::get('retailer');
$dates = Input::get('obs');
$sales= Input::get('sales');
Buy now you try to forcibly insert them into the database. Why not use eloquent for database insertion: (Keep in mind you'd need to have a model for the charts table called Chart.php)
$chart = new Chart;
$chart->sku = $sku;
$chart->retailer = $retailer;
$chart->dates = $dates;
$chart->save();
That being said, I do realize that you're trying to pass arrays to the database, so that might take some experimentation. If you can't figure out what's (attempting) being passed to the database, you can always use:
die($variable);
To check what's up. Good luck!

How to sort json type data using javascript?

I have 3 dropdowns with list of places that I wanted to sort in ascending order. The first dropdown of places is sorted using codeigniter active record order_by function and the places were successfully sorted in ascending order.However,using onchange javascript function,when I choose a place in the first dropdown then populate the second dropdown of places excluding the place I have chosen in the first dropdown, the places returned were not sorted in ascending order even though there is order_by function I have in my query. I suspect that this is because of the json formatted data returned in onchange. Here are my codes. Thanks for the help.
This code sorts the data properly in ascending order
function get_dropdown_barangay(){
$query = $this->db->select('ID,brgy_name')
->from('tbl_barangay')
->order_by('brgy_name','asc')
->get()
->result_array();
$dropdown = array('0'=>'Select Barangay');
foreach($query as $value){
$dropdown[$value['ID']] = $value['brgy_name'];
}
return $dropdown;
}
Output Image:
Onchange code, the returned places are not sorted in ascending order
$('#brgy_id_1').change(function(){
var brgy_id = $("#brgy_id_1").val();
alert(brgy_id);
var data_val = {'brgy_id':brgy_id};
$.ajax({
type: "POST",
url:"<?php echo base_url();?>admin/get_barangay_list",
data:data_val,
dataType:'json',
success: function(data)
{
$('#brgy_id_2').empty();
$.each(data,function(id,val)
{
var opt = $('<option />'); // here we're creating a new select option for each group
opt.val(id);
opt.text(val);
$('#brgy_id_2').append(opt);
});
}
});
}); //end change
admin.php
function get_barangay_list(){
if(isset($_POST['brgy_id2'])){
$brgy_array_id = array('0'=>$_POST['brgy_id'],'1'=>$_POST['brgy_id2']);
} else{
$brgy_array_id = array('0'=>$_POST['brgy_id']);
}
$result=$this->core_model->get_barangay_list($brgy_array_id);
$this->output->set_header('Content-Type: application/json',true);
echo json_encode($result);
}
model.php
function get_barangay_list($brgy_array_id){
$query = $this->db->select('ID,brgy_name')
->from('tbl_barangay')
->where_not_in('ID',$brgy_array_id)
->order_by('brgy_name','asc')
->get()
->result_array();
$dropdown = array('0'=>'Select Barangay');
foreach($query as $value){
$dropdown[$value['ID']] = $value['brgy_name'];
}
return $dropdown;
}
Output Image showing data are not sorted in ascending order
One way to implement kinghfb's comment :
On the server side : build an array
$dropdown = array();
$dropdown[] = array('id' => 0, 'label' => 'Select city');
for ($query as $value) {
$dropdown[] = array('id' => $value['ID'], 'label' => $value['brgy_name']);
}
On the client side (javascript) : change your loop code :
$.each(data,function(id,val) {
var opt = $('<option />'); // here we're creating a new select option for each group
opt.val(val.id);
opt.text(val.label);
$('#brgy_id_2').append(opt);
});
You are losing your order here, because you are setting new keys (problem is described here Change array key without changing order).
So you have to keep the keys and due this you have to change the js part as well, because you can´t access the data using key-value anymore.
function get_dropdown_barangay(){
$query = $this->db->select('ID,brgy_name')
->from('tbl_barangay')
->order_by('brgy_name','asc')
->get()
->result_array();
$dropdown = array('0'=>'Select Barangay');
foreach($query as $value){
$dropdown[] = array("id" => $value["ID"], "name" => $value['brgy_name']); // setting new value and keep an numeric key which represents the order
}
return $dropdown;
}
and the js has to be like:
$('#brgy_id_1').change(function(){
var brgy_id = $("#brgy_id_1").val();
alert(brgy_id);
var data_val = {'brgy_id':brgy_id};
$.ajax({
type: "POST",
url:"<?php echo base_url();?>admin/get_barangay_list",
data:data_val,
dataType:'json',
success: function(data)
{
$('#brgy_id_2').empty();
$.each(data,function(object)
{
var opt = $('<option />'); // here we're creating a new select option for each group
opt.val(object.id);
opt.text(object.value);
$('#brgy_id_2').append(opt);
});
}
});
});
I had highlighted the changes, but I don´t know hot to use bold in code at SO....
You could sort your JSON using underscore
Just pass in your JSON and a sort function. Like so:
var cityJSON = [{city: 'San Vinente'}, {city: 'Pequnio'}, {city: 'Pili Drive'}, {city: 'Jc Aquino'}, {city: 'Banza'}];
console.log(cityJSON); // unsorted
cityJSON = _.sortBy(cityJSON, function(item){return item.city});
console.log(cityJSON); // sorted

Categories