I am trying to write an app that will allow people to insert data into a form and this will draw a chart via Chart.js I am ok if there are not multiple datasets but when there are I look for a '/' and put values into an array. The problem I am having is I cant seem to get this form data. ie The chart I load initially has the two datasets properly setup. But I have tried using this code:
formData[index].value.forEach(function (value, dataset_index) {
console.log(formData[index].name);
chartData.datasets[dataset_index][formData[index].name] = value; // Problem Line
I get error "TypeError: chartData.datasets[dataset_index] is undefined". I have tried multiple permutations on this bracket notation and get similar errors.
// /public/main.js
const chartData = {
labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'],
datasets: [{
label: 'apples',
data: [12, 19, 3, 17, 6, 3, 7],
backgroundColor: "rgba(153,255,51,0.4)"
}, {
label: 'oranges',
data: [2, 29, 5, 5, 2, 3, 10],
backgroundColor: "rgba(255,153,0,0.4)"
}]
};
let Options = {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
};
const ctx = document.getElementById("myChart").getContext('2d');
let myChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: Options
});
// Get Chart Info from form
$(document).ready(function() {
$("#render_btn").on("click", function(e) {
e.preventDefault();
// First grab form data off the page
const formData = $('form').serializeArray();
// Get Chart Type and Options Seperate from Form Data
const chartTypeControl = document.getElementById("chart_type");
const chartType = chartTypeControl.options[chartTypeControl.selectedIndex].value;
Options = document.getElementById("chart_options").value;
// Create a data Object for Chart constructor to use
let datasetsItem = {};
// Convert formData array to chartData object
formData.forEach(function(value, index) {
if (formData[index].name == 'labels' || formData[index].name == 'options') {
chartData[(formData[index].name)] = formData[index].value;
} else {
// Check if this form value has multiple datasets(has a '/') and if so
// split the string into seperate dataset's
if (formData[index].value.indexOf('/') > -1) {
// Split the field up into seperate array items
formData[index].value = splitString(formData[index].value, '/');
// Now put the array items into their seperate datasets
formData[index].value.forEach(function (value, dataset_index) {
datasetsItem[formData[index].name] = value;
// console.log(datasetsItem[formData[index].name]);
chartData.datasets[dataset_index] = datasetsItem;
});
} else {
datasetsItem[formData[index].name] = formData[index].value;
chartData.datasets[0] = datasetsItem;
}
}
});
// =====================================================================================
// Now we have to do some converting i.e., chartData.labels must be converted to array
// from string etc.. ==================================================================
chartData.datasets[0].backgroundColor = splitString(chartData.datasets[0].backgroundColor);
chartData.datasets[0].borderColor = splitString(chartData.datasets[0].borderColor);
chartData.datasets[0].data = strToNumberArray(chartData.datasets[0].data);
chartData.labels = splitString(chartData.labels);
chartData.datasets[0].borderWidth = strToNumber(chartData.datasets[0].borderWidth);
if (isNaN(chartData.datasets[0].borderWidth)) {
alert("Attention: Border Width needs to be a number.");
}
// Check if successful
try {
if (!(chartData.datasets[0].data) || !(chartData.labels)) {
throw new Error("Input Error. Recheck your form data.");
}
myChart.type = chartType;
myChart.data = chartData;
myChart.update();
} catch (error) {
alert(error);
}
// ============================================================= //
// ============= Function definitions ========================== //
// ============================================================= //
function splitString(strToSplit, separator = ",") {
if (!strToSplit) {
alert("Error: One of your required fields is empty.");
return "";
}
// Test for a ',' or '/' slash in the string
const result = /[,\/]/g.test(strToSplit);
if (!result) {
// Only one entry in Data form
return strToSplit;
}
// Split a string into an array and trim any whitespace
let arrayOfStrings = strToSplit.split(separator);
arrayOfStrings.forEach(function(value, index) {
arrayOfStrings[index] = value.trim();
});
return arrayOfStrings;
}
// Function to convert string to an array then convert each element to a number
function strToNumberArray(str, separator = ',') {
if (str === undefined) {
alert('Error: string is empty.');
return "";
}
// Test for a comma in the string
const result = /,+/.test(str);
if (!result) {
alert(`Comma delimiter missing from ${str}`);
return false;
}
let arrayOfNumbers = str.split(separator).map(Number);
return arrayOfNumbers;
}
// Function convert string type to number
function strToNumber(str) {
Number(str);
return str;
}
// Functtion remove all whitespace from string
function removeWhiteSpace(str) {
str.replace(/\s+/g, '');
return str;
}
// ============================================================== //
// ================== End Function Definitions ================== //
// ============================================================== //
}); // End .on "click"
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<canvas id="myChart" width="400" height="400"></canvas>
<h2>Input your values:</h2>
<!-- Chart Input Form -->
<!-- We dont want chart_type as part of form when we use serializeArray
gather the data and use in chartData object -->
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="form-group">
<label for="chart_type">Chart Type</label>
<input type="text" name="type" class="form-control" id="chart_type" placeholder="Chart Type">
</div>
</div>
</div>
<form>
<div class="row">
<div class="col-md-4 col-md-offset-4 ">
<div class="form-group">
<label for="chart_type">Chart Type</label>
<select class="form-control input-lg" id="chart_type">
<option value="bar">Bar Chart</option>
<option value="pie">Pie Chart</option>
<option value="line">Line</option>
<option value="doughnut">Doughnut</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="form-group">
<label for="chart_Label">Chart Label</label>
<input type="text" name="label" class="form-control input-lg" id="chart_Label" placeholder="Chart Label">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="chart_labels">Chart Labels</label>
<input type="text" name="labels" class="form-control input-lg" id="chart_labels" placeholder="Apr, May, June Note:Seperated by Commas">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="chart_data">Chart Data</label>
<input type="text" name="data" class="form-control input-lg" id="chart_data" placeholder="i.e., 25 44 60 etc">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="chart_colors">Chart Colors</label>
<input type="text" name="backgroundColor" class="form-control input-lg" id="chart_colors" placeholder="i.e., red, blue, yellow, purple">
</div>
</div>
</div>
<!-- ============ More Options Markup ================================== -->
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#more_options" aria-expanded="false" aria-controls="collapseExample">
More Options
<span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
</button>
<div class="collapse" id="more_options">
<div class="well">
<div class="row">
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="border_color">Border Color(s)</label>
<input type="text" name="borderColor" class="form-control input-lg" id="border_color" placeholder="i.e., red,blue,green,orange">
</div>
</div>
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="border_width">Border Width</label>
<input type="text" name="borderWidth" class="form-control input-lg" id="border_width" placeholder="i.e., 1">
</div>
</div>
</div>
<!-- Options Markup -->
<div class="col-md-6 col-md-offset-4">
<div class="form-group">
<label for="chart_options">Chart Options</label>
<input type="text" name="options" class="form-control input-lg" id="chart_options" placeholder="See Chart.js Documentation">
</div>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-md-4 col-md-offset-5">
<button class="btn btn-primary btn-lg" id="render_btn">
<span class="glyphicon glyphicon-stats" aria-hidden="true"></span>
Render Graph
</button>
</div>
</div>
Long story short I cant seem to store the apples/oranges or any other values that are in multiple datasets into the chartData object array properly. Any help/insight much appreciated.
Update:
Yes I can now see the dataset array in chartData but it is incorrect. See image:
It would seem chartData.datasets{0] and 1 are exactly the same?? I updated the snippet. When I console.log datasets in the forEach I get the right values spitting out. Any suggestions ? Thanks.
From a glance, at your problem line, chartData.datasets[dataset_index] is not defined yet (as the error tells). You need to assign the element at that index. At the point you'll be trying to set the object key via a variable as seen here. So something like this should work:
var data = {};
data[formData[index].name] = value;
chartData.datasets[dataset_index] = data;
Related
I am trying to create a simple application to request a car key for a service department. Obviously the code could be written better, but this is my third day with Vue.js. The time function that is called in the first p tag in the code updates every minutes to keep count of an elapsed time. The problem I am having is when I request a new key the time function doesn't follow the array items as intended. For example, if there are no other requests the first request I submit works perfectly. However, when I submit a new request the elapsed time from my first request goes to my second request. I am sure it could have something to do with the glued together code, but I have tried everything I can think of. Any help would be appreciated.
<template>
<div class="row">
<div class="card col-md-6" v-for="(key, index) in keys" :key="index">
<div class="card-body">
<h5 class="card-title">Service Tag: {{ key.service_tag }}</h5>
<p class="card-text"> {{time}} {{key.reqTimestamp}}min</p>
<p class="invisible">{{ start(key.reqTimestamp) }}</p>
<p class="card-text">Associates Name: {{key.requestor_name}}</p>
<p class="card-text">Model: {{key.model}}</p>
<p class="card-text">Color: {{key.color}}</p>
<p class="card-text">Year: {{key.year}}</p>
<p class="card-text">Comments: {{key.comments}}</p>
<p class="card-text">Valet: {{key.valet}}</p>
<input class="form-control" v-model="key.valet" placeholder="Name of the person getting the car...">
<button
#click="claimedKey(key.id, key.valet)"
type="submit"
class="btn btn-primary"
>Claim</button>
<button v-if="key.valet !== 'Unclaimed'"
#click="unclaimedKey(key.id, key.valet)"
type="submit"
class="btn btn-primary"
>Unclaim</button>
<button class="btn btn-success" #click="complete(key.id)">Complete</button>
</div>
</div>
<!-- END OF CARD -->
<!-- START OF FORM -->
<div class="row justify-content-md-center request">
<div class="col-md-auto">
<h1 class="display-4">Operation Tiger Teeth</h1>
<form class="form-inline" #submit="newKey(service_tag, requestor_name, comments, model, year, color, valet, reqTimestamp)">
<div class="form-group col-md-6">
<label for="service_tag">Service Tag: </label>
<input class="form-control form-control-lg" v-model="service_tag" placeholder="ex: TB1234">
</div>
<div class="form-group col-md-6">
<label for="service_tag">Associates Name: </label>
<!-- <input class="form-control form-control-lg" v-model="requestor_name" placeholder="Your name goes here..."> -->
<div class="form-group">
<label for="exampleFormControlSelect1">Example select</label>
<select v-model="requestor_name" class="form-control" id="requestor_name">
<option>James Shiflett</option>
<option>Austin Hughes</option>
</select>
</div>
</div>
<div class="form-group col-md-6">
<label for="service_tag">Model: </label>
<input class="form-control form-control-lg" v-model="model" placeholder="What is the model of the vehicle?">
</div>
<div class="form-group col-md-6">
<label for="service_tag">Color: </label>
<input class="form-control form-control-lg" v-model="color" placeholder="What is the color of the vehicle?">
</div>
<div class="form-group col-md-6">
<label for="service_tag">Year: </label>
<input class="form-control form-control-lg" v-model="year" placeholder="What year is the car?">
</div>
<div class="form-group col-md-6">
<label for="service_tag">Comments: </label>
<input class="form-control form-control-lg" v-model="comments" placeholder="Place any additional comments here...">
</div>
<div class="form-group col-md-6 invisible">
<label for="service_tag">Valet: </label>
<input v-model="valet">
</div>
<div class="form-group col-md-6 invisible">
<label for="service_tag">Timestamp: </label>
<input v-model="reqTimestamp">
</div>
<div class="col-md-12">
<button class="btn btn-outline-primary" type="submit">Request A Key</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import { db } from "../main";
import { setInterval } from 'timers';
export default {
name: "HelloWorld",
data() {
return {
keys: [],
reqTimestamp: this.newDate(),
service_tag: "",
requestor_name: "",
comments: "",
color: "",
model: "",
year: "",
inputValet: true,
valet: "Unclaimed",
state: "started",
startTime: '',
currentTime: Date.now(),
interval: null,
};
},
firestore() {
return {
keys: db.collection("keyRequests").where("completion", "==", "Incomplete")
};
},
methods: {
newKey(service_tag, requestor_name, comments, model, year, color, valet, reqTimestamp, completion) {
// <-- and here
db.collection("keyRequests").add({
service_tag,
requestor_name,
comments,
color,
model,
year,
valet,
reqTimestamp,
completion: "Incomplete",
});
this.service_tag = "";
this.requestor_name = "";
this.comments = "";
this.color = "";
this.model = "";
this.year = "";
this.reqTimestamp = this.newDate()
},
complete(id) {
db.collection("keyRequests").doc(id).update({
completion: "Complete"
})
},
// deleteKey(id) {
// db.collection("keyRequests")
// .doc(id)
// .delete();
claimedKey(id, valet) {
console.log(id);
this.inputValet = false
db.collection("keyRequests").doc(id).update({
valet: valet,
claimTimestamp: new Date()
})
},
moment: function () {
return moment();
},
newDate () {
var today = new Date()
return today
},
updateCurrentTime: function() {
if (this.$data.state == "started") {
this.currentTime = Date.now();
}
},
start(timestamp) {
return this.startTime = timestamp.seconds * 1000
}
},
mounted: function () {
this.interval = setInterval(this.updateCurrentTime, 1000);
},
destroyed: function() {
clearInterval(this.interval)
},
computed: {
time: function() {
return Math.floor((this.currentTime - this.startTime) /60000);
}
}
}
</script>
Ideally I am looking for the time lapse to follow each request.
So the problem lines in the template are:
<p class="card-text"> {{time}} {{key.reqTimestamp}}min</p>
<p class="invisible">{{ start(key.reqTimestamp) }}</p>
The call to start has side-effects, which is a major no-no for rendering a component. In this case it changes the value of startTime, which in turn causes time to change. I'm a little surprised this isn't triggering the infinite rendering recursion warning...
Instead we should just use the relevant data for the current iteration item, which you've called key. I'd introduce a method that calculates the elapsed time given a key:
methods: {
elapsedTime (key) {
const timestamp = key.reqTimestamp;
const startTime = timestamp.seconds * 1000;
return Math.floor((this.currentTime - startTime) / 60000);
}
}
You'll notice this combines aspects of the functions start and time. Importantly it doesn't modify anything on this.
Then you can call it from within your template:
<p class="card-text"> {{elapsedTime(key)}} {{key.reqTimestamp}}min</p>
I am attempting to have the user inputs( first name, last name, contract number, amount) pass to payment.php and then be sent via $result = Braintree_Transaction::sale but payment_method_nonce is the only thing that passes to payment.php. When test payment.php with <?php print_r($_POST); ?> I only receive Array ( [payment_method_nonce] => 9ce4f24f-9746-076c-760b-d30d18a3cdf5 ) Thanks in advance Here is my code:
HTML
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default bootstrap-basic">
<div class="panel-heading">
<h3 class="panel-title">Enter Payment Details</h3>
</div>
<form class="panel-body" id="paymentportal" action="payment.php" method="post">
<div class="row">
<div class="form-group col-sm-6">
<label class="control-label">First Name</label>
<!-- Hosted Fields div container -->
<input type="text" placeholder="John" class="form-control" id="first-name">
</div>
<div class="form-group col-sm-6">
<label class="control-label">Last Name</label>
<!-- Hosted Fields div container -->
<input type="text" placeholder="Doe" class="form-control" id="last-name">
</div>
</div>
<div class="row">
<div class="form-group col-sm-6">
<label class="control-label">Contract Number</label>
<!-- Hosted Fields div container -->
<input type="text" placeholder="1462" class="form-control" id="order-number">
</div>
<div class="form-group col-sm-6">
<label class="control-label">Amount</label>
<!-- Hosted Fields div container -->
<input type="text" placeholder="$1234.56" class="form-control" id="amount">
</div>
</div>
<div class="row">
<div class="form-group col-sm-8">
<label class="control-label">Card Number</label>
<!-- Hosted Fields div container -->
<div class="form-control" id="card-number"></div>
<span class="helper-text"></span>
</div>
<div class="form-group col-sm-4">
<div class="row">
<label class="control-label col-xs-12">Expiration Date</label>
<div class="col-xs-6">
<!-- Hosted Fields div container -->
<div class="form-control" id="expiration-month"></div>
</div>
<div class="col-xs-6">
<!-- Hosted Fields div container -->
<div class="form-control" id="expiration-year"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-sm-6">
<label class="control-label">Security Code</label>
<!-- Hosted Fields div container -->
<div class="form-control" id="cvv"></div>
</div>
<div class="form-group col-sm-6">
<label class="control-label">Zipcode</label>
<!-- Hosted Fields div container -->
<div class="form-control" id="postal-code"></div>
</div>
</div>
<input type="hidden" name="payment_method_nonce" id="payment_method_nonce">
<button value="btnSubmit" id="btnSubmit" class="btn-box center-block">Pay with <span id="card-type">Card</span></button>
</form>
</div>
</div>
JS
var form = document.getElementById('paymentportal');
braintree.client.create({
authorization: 'sandbox_authorization'
}, function (err, clientInstance) {
if (err) {
console.error(err);
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '14px',
'font-family': 'helvetica, tahoma, calibri, sans-serif',
'color': '#3a3a3a'
},
':focus': {
'color': 'black'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: '4111 1111 1111 1111'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationMonth: {
selector: '#expiration-month',
placeholder: 'MM'
},
expirationYear: {
selector: '#expiration-year',
placeholder: 'YY'
},
postalCode: {
selector: '#postal-code',
placeholder: '90210'
}
}
}, function (err, hostedFieldsInstance) {
if (err) {
console.error(err);
return;
}
hostedFieldsInstance.on('validityChange', function (event) {
var field = event.fields[event.emittedBy];
if (field.isValid) {
if (event.emittedBy === 'expirationMonth' || event.emittedBy === 'expirationYear') {
if (!event.fields.expirationMonth.isValid || !event.fields.expirationYear.isValid) {
return;
}
} else if (event.emittedBy === 'number') {
$('#card-number').next('span').text('');
}
// Remove any previously applied error or warning classes
$(field.container).parents('.form-group').removeClass('has-warning');
$(field.container).parents('.form-group').removeClass('has-success');
// Apply styling for a valid field
$(field.container).parents('.form-group').addClass('has-success');
} else if (field.isPotentiallyValid) {
// Remove styling from potentially valid fields
$(field.container).parents('.form-group').removeClass('has-warning');
$(field.container).parents('.form-group').removeClass('has-success');
if (event.emittedBy === 'number') {
$('#card-number').next('span').text('');
}
} else {
// Add styling to invalid fields
$(field.container).parents('.form-group').addClass('has-warning');
// Add helper text for an invalid card number
if (event.emittedBy === 'number') {
$('#card-number').next('span').text('Looks like this card number has an error.');
}
}
});
hostedFieldsInstance.on('cardTypeChange', function (event) {
// Handle a field's change, such as a change in validity or credit card type
if (event.cards.length === 1) {
$('#card-type').text(event.cards[0].niceType);
} else {
$('#card-type').text('Card');
}
});
$('.panel-body').submit(function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (err, payload) {
if (err) {
console.error(err);
return;
}
document.querySelector('input[name="payment_method_nonce"]').value = payload.nonce;
// This is where you would submit payload.nonce to your server
form.submit();
});
});
});
});
PHP
<?php
$result = Braintree_Transaction::sale([
'amount' => $_POST['amount'],
'orderId' => $_POST['order-number'],
'paymentMethodNonce' => $_POST['payment_method_nonce'],
'customer' => [
'firstName' => $_POST['first-name'],
'lastName' => $_POST['last-name'],
],
'options' => [
'submitForSettlement' => true
]
]);
if ($result->success === true){
}else
{
print_r($result->errors);
die();
}
?>
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact
support.
Remember when you collect form data on your server, you need to reference those inputs by their name attribute. Once you add the respective name values to each of these inputs, it should work as expected.
For example, your first name input;
<input type="text" placeholder="John" class="form-control" id="first-name" name="first-name">
I'm new to MVC and AJAX so this is probably a simple mistake I am making but using the code below, I am getting the following error trying to getElementById("txtCount").value:
<div class="row">
<div class="col-sm-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h5 style="font-weight:bold;">Parameters</h5>
</div>
<div class="panel-body" id="parameters">
<form class="form-horizontal" id="frmParameters">
<div class="form-group">
<label for="txtCount" class="col-sm-4 col-form-label">Repeat</label>
<input type="number" min="1" max="100" step="1" id="txtCount" value="#Model.Count" class="input-sm col-sm-7" />
</div>
#if (Model.Grammar.SupportsMaxLength)
{
<div class="form-group">
<label for="txtMaxLength" class="col-sm-4 col-form-label">Max Length</label>
<input type="number" min="1" max="100" step="1" id="txtMaxLength" value="#Model.MaxLength" class="input-sm col-sm-7" />
</div>
}
<button name="btnGenerate" class="btn btn-primary pull-right" onclick="Generate();">Generate</button>
</form>
</div>
</div>
</div>
</div>
<script>
function Generate() {
var data = { count: document.getElementById("txtCount").value, maxLength: document.getElementById("txtMaxLength").value };
}
</script>
If I change:
var data = { count: document.getElementById("txtCount").value, maxLength: document.getElementById("txtMaxLength").value };
to:
var data = { count: document.getElementById("txtCount").value};
I don't get the error anymore.
Your code looks fine. I think you are getting the error when your code tries to execute this line
document.getElementById("txtMaxLength").value
Because in your view you are rendering this element when some if condition returns true. So it is possible that your view does not have this input element at all and you are trying to read that! (Check the view source of the page and search for input with txtMaxLength id.
The best solution is to check it exists before trying to read the value.
var data = {
id: "#Model.Id",
count: document.getElementById("txtCount").value,
maxLength: null // or whatever default value you want
};
if (document.getElementById("txtMaxLength")) {
data2.maxLength = document.getElementById("txtMaxLength").value;
}
Or if you are using jQuery library, it is easy
var data = {
id: "#Model.Id",
count: $("#txtCount").val(),
maxLength:$("#txtMaxLength").val()
};
Here's what I need to do.
I need to create an array of array of objects like the format below. I am getting name and values of input boxes and put then in a json then push it in an array and then I push the generated array into another array.
[
[
{"key1":"value1","key2":"value2"},
{"key1":"value3","key2":"value4"},
],
[
{"key1":"value1","key2":"value2"},
{"key1":"value1","key2":"value2"},
]
]`
below is my code
$scope.saveImages = function(){
var arrayOfArrays =[];
var arrayOfPhotos = [];
angular.element('.photo-group').each(function(){
var object = {};
$(this).find('.photo').each(function(){
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
});
arrayOfPhotos.push(object)
arrayOfArrays.push(arrayOfPhotos)
console.log(arrayOfArrays)
});
}
and this is my markup
<div class="photo-group">
<div class="photo-group-body">
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="photo-group">
<div class="photo-group-body">
<div class="initial-photo">
<div class="row no-padding new-photo">
<div class="col no-padding">
<div class="form-group no-right-padding">
<label class="label-control" class="label-control">Label</label>
<input type="text" name="photo_label" class="form-control photo">
<input type="text" name="image_data" class="form-control photo photo_data">
</div>
</div>
</div>
</div>
</div>
</div>
In my markup I have two .photo-group classes.
on the first .photo-group class I have four .photo class
and on the second .photo-group class I have two .photo class
so my array should look like this
[
[
{"photo_label":"value1", "image_data":"value2"},
{"photo_label":"value3", "image_data":"value4"},
],
[
{"photo_label":"value4", "image_data":"value5"},
]
]`
but instead, what I get is only the last objects in each array
[
[
{"photo_label":"value3", "image_data":"value4"},
],
[
{"photo_label":"value4", "image_data":"value5"},
]
]`
creat the pushing object inside foreach
angular.element('.photo-group').each(function(){
$(this).find('.photo').each(function(){
var object = {};
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
arrayOfPhotos.push(object);
});
arrayOfArrays.push(arrayOfPhotos);
console.log(arrayOfArrays);
});
So after hours of trial and error testing and tracing the flow of the code.. I was able to get what I want.
Here's what I did
$scope.saveImages = function(){
var arrayOfArrays =[];
angular.element('.photo-group').each(function(){
var arrayOfPhotos = [];
$(this).find('.initial-photo').each(function(){
var object = {};
$(this).find('.photo').each(function(){
var key = $(this).attr('name');
var value = $(this).val();
object[key] = value;
});
arrayOfPhotos.push(object)
});
arrayOfArrays.push(arrayOfPhotos);
});
}
I added another loop to go deep into the child elements and place the var arrayOfPhotos = []; in the first instance of the loop
I am trying to modify my css with settings which I received from an object.
I send the object after the user select the options from a form.
Now I want to use this to change my layout, but I don't know exactly how.
My template looks like this
div class="btn btn-primary" ng-click="showMenu()">Layout Settings</div>
<div ng-show="themeSelected">
<form>
<div class="row">
<div>
<div class="form-group">
<label>Background color for views</label>
<input type="text" name="background_color" id="background_color" ng-model="selectedLayout.background_color" class="form-control" />
</div>
<div class="form-group">
<label>Background image</label>
<input type="file" name="background_image" id="background_image" ng-model="selectedLayout.background_image" class="form-control" style="width:25%" />
</div>
<div class="form-group">
<label>Buttons color</label>
<input type="text" name="buttons_color" id="buttons_color" ng-model="selectedLayout.buttons_color" class="form-control" />
</div>
<div class="form-group">
<label>Buttons size</label>
<input type="text" name="buttons_size" id="buttons_size" ng-model="selectedLayout.buttons_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Buttons font color</label>
<input type="text" name="buttons_font_color" id="buttons_font_color" ng-model="selectedLayout.buttons_font_color" class="form-control" />
</div>
<div class="form-group">
<label>Headers size</label>
<input type="text" name="headers_size" id="headers_size" ng-model="selectedLayout.headers_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Headers color</label>
<input type="text" name="headers_color" id="headers_color" ng-model="selectedLayout.headers_color" class="form-control" />
</div>
<div class="form-group">
<label>Info size</label>
<input type="text" name="info_size" id="info_size" ng-model="selectedLayout.info_size" class="form-control" placeholder="13px" style="width:5%" />
</div>
<div class="form-group">
<label>Info font color</label>
<input type="text" name="info_font_color" id="info_font_color" ng-model="selectedLayout.info_font_color" class="form-control" />
</div>
</div>
</div>
</form>
<button class="btn btn-primary" ng-click="saveChanges(selectedLayout)">Save</button>
<button class="btn btn-primary" ng-click="cancel()">Cancel</button>
<div style="color: red" ng-show="errors.length > 0">{{errors}}</div>
</div>
And when I press Save button all those defined above are in an object. Now I want to use those settings to actually change my layout.
This is my controller where i defined the saveChanges
'use strict';
(function () {
angular.module('routerApp').controller('LayoutController', function ($scope,layoutRepository) {
$scope.showMenu = function() {
$scope.themeSelected = true;
};
$scope.cancel = function() {
$scope.themeSelected = false;
};
$scope.saveChanges = function (selectedLayout) {
layoutRepository.saveLayoutInfo(selectedLayout);
$scope.themeSelected = false;
};
$scope.selectedLayout = {};
window.model = $scope.selectedLayout;
});
}());
This is the layoutRepository
'use strict';
(function () {
angular.module('routerApp').factory('layoutRepository', function ($http) {
return {
saveLayoutInfo: function (selectedLayout) {
console.log(selectedLayout);
$http({
method: "POST",
url: "/api/LayoutSettings",
data: selectedLayout,
cache: false
});
}
};
});
}());
You can use this. It will take your data, retrieve the classnames, keys and values from it and appends it to the correct element:
var data = data.split("\n"); //split the received data on a new line
for (var i = 0; i < data.length; i++)
{
var className = data[i].substr(0, data[i].indexOf("_")); //classname = part before the "_"
var csskey = data[i].substr(data[i].indexOf("_")+1, data[i].indexOf(":");
var cssvalue = data[i].substr(data[i].indexOf(":")+1).trim().replace("\"",""); strip whitespaces and quotations
loadCSSIntoControl(className, {key:csskey, value : cssvalue });
}
function loadCSSIntoControl(classname, css)
{
if (css.key == "size")
{
css.key = "font-size";
}
//iterate over all elements using Array.prototype.map
Array.prototype.map.call(document.querySelectorAll("."+classname), function(elem) {
elem.style[css.key.replace("_", "-")] = css.value; //replace underscore with dash
});
}
Note: if the first part isn't a class name, you can easily change this to another type of selector.
Bind the settings to a scope (are they an object/json? Your output seems odd)
<button data-ng-style="{
background: selectedLayout.buttons_color,
color: selectedLayout.buttons_font_color,
fontSize: selectedLayout.buttons_size
}">Button</button>
This is assuming the data looks like this:
selectedLayout = {
buttons_color: "rgb(83, 255, 0)",
buttons_font_color: "rgb(255, 247, 0)",
buttons_size: "11px",
headers_color: "rgb(187, 52, 202)",
headers_size: "18px",
info_font_color: "rgb(17, 15, 15)",
info_size: "12px"
}