My nested elements are throwing errors. what am I doing wrong? - reactjs

The following block renders correctly in the Gutenberg's Block Editor.
registerBlockType('mytheme/rima-preface', {
title: 'Custom block',
description: 'My first block',
category: 'layout',
edit() {
var blockProps = useBlockProps();
return el("div", {
class: "section"
}, el("div", {
class: "container"
}, el("div", {
class: "row align-items-center col-spacing-50"
}, el("div", {
class: "col-12 col-md-6"
}, el("div", {
...blockProps
}, el(InnerBlocks)))
)))
},
save() {
var blockProps = useBlockProps.save();
return el("div", {
class: "section"
}, el("div", {
class: "container"
}, el("div", {
class: "row align-items-center col-spacing-50"
}, el("div", {
class: "col-12 col-md-6"
}, el("div", {
...blockProps
}, el(InnerBlocks.Content)))
)))
}
});
However, as soon as I edit and save it, it shows the following errors on page reload:
Block validation: Expected attribute `class` of value `wp-block-mytheme-rima-preface`, saw `section`.
Block validation: Block validation failed for `mytheme/rima-preface` ({name: "mytheme/rima-preface", icon: {…}, keywords: Array(0), attributes: {…}, providesContext: {…}, …}).
Content generated by `save` function:
<div class="section" class="wp-block-mytheme-rima-preface"><div class="container"><div class="row align-items-center col-spacing-50"><div class="col-12 col-md-6"><div class="wp-block-mytheme-rima-preface"></div></div></div></div></div>
Content retrieved from post body:
<div class="section" class="wp-block-mytheme-rima-preface"><div class="container"><div class="row align-items-center col-spacing-50"><div class="col-12 col-md-6"><div class="wp-block-mytheme-rima-preface">
</div></div></div></div></div>
I've been trying to solve the issue for 30 minutes, anyone that can point me in the right direction?

Related

How to get value from array, which is inside objects in react js?

I'm trying to get values from an array,
which is inside of objects:
const post = {
sticky: false,
template: "",
format: "standard",
_embedded: {
author: [{
0: {
id: 2,
name: "Charlie"
}
}],
term: ""
}
}
I need to get value of author.name, how should I map through this?
I tried this in my return:
return(
<div className={className}>
<h2>
{post._embedded.author[0].name}
</h2>
</div>
)
But it's not working, I get an error Cannot read property 'author' of undefine.
Sorry for silly question, but it's hard for me to understand.
This should work
post._embedded.author[0]['0'].name
You can try it out using the below snippet.
const post = {
sticky: false,
template: "",
format: "standard",
_embedded: {
author: [{
0: {
id: 2,
name: "Charlie"
}
}],
term: ""
}
};
const name = post._embedded.author[0]['0'].name;
console.log(name)
So the jsx would be
return(
<div className={className}>
<h2>
{post._embedded.author[0]['0'].name}
</h2>
</div>
)

ComponentDidUpdate causing infinite render even when wrapped in condition

I'm trying to pull some data from Google Analytics reporting API and display the data inside the apex charts library. I managed to successfully do this. However, I now want filtering options to where if the user selects a certain date within the date range picker react wrapper, the apex charts data gets updated from the API.
I'm struggling figuring out on how when my data gets updated, to update the state with the new state within my life cycle method? I think I'm doing something minor I just don't know what it is. I looked up the documentation on the life cycle method and it says to make sure to wrap it inside a condition which I did. However, when the else condition is met, it causes an infinite render.
Here is my code: (the bug i'm stuck on is the componentWillUpdate lifecycle method) everything else works fine.
import React from "react";
import Header from "../common/Header";
import Footer from "../common/Footer";
import moment from "moment";
import $ from "jquery";
import ApexCharts from "apexcharts";
import Chart from "react-apexcharts";
import DateRangePicker from "react-bootstrap-daterangepicker";
const VIEW_ID = "";
class Charts extends React.Component {
constructor(props) {
super(props);
this.printResults = this.printResults.bind(this);
this.pageViews = this.pageViews.bind(this);
this.handleError = this.handleError.bind(this);
this.state = {
loading: true,
filterstartDate: "",
filterendDate: "",
// Start Series Bar State
ChartOne: {
chart: {
id: "ChartOne"
},
colors: ["#e31d1a"],
xaxis: {
categories: [],
labels: {
style: {
colors: []
}
},
title: {
text: "Locations"
}
},
yaxis: {
labels: {
style: {
colors: []
}
},
title: {
text: "Count"
}
}
},
ChartOneSeries: [],
}
pageViews = async () => {
window.gapi.client
.request({
path: "/v4/reports:batchGet",
root: "https://analyticsreporting.googleapis.com",
method: "POST",
body: {
reportRequests: [
{
viewId: VIEW_ID,
dateRanges: [
{
startDate: "7daysAgo",
endDate: "today"
}
],
metrics: [
{
expression: "ga:pageviews"
}
],
dimensions: [
{
name: "ga:country"
}
],
orderBys: [{ fieldName: "ga:pageviews", sortOrder: "DESCENDING" }]
}
]
}
})
.then(this.printResults, this.handleError);
};
componentDidMount() {
$.getScript("https://apis.google.com/js/client:platform.js").done(() => {
window.gapi.signin2.render("my-signin2", {
scope: "profile email",
width: 240,
height: 50,
longtitle: true,
theme: "dark",
onsuccess: this.pageViews,
onfailure: this.handleError
});
});
}
//log the data
printResults(response) {
let pageviewLocation = [];
let pageviewCount = [];
let pageviewTotal = response.result.reports[0].data.totals[0].values[0];
let totalComma = pageviewTotal
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
response.result.reports[0].data.rows.map(value => {
//console.log(value.dimensions);
pageviewLocation.push(value.dimensions[0]);
pageviewCount.push(parseInt(value.metrics[0].values[0]));
});
//console.log(total);
this.setState({
loading: false,
ChartOne: {
title: {
text: totalComma,
align: "center",
style: {
fontSize: "20px"
}
},
subtitle: {
text: "Total Page Views",
align: "center",
style: {
fontSize: "14px",
cssClass: "apexcharts-yaxis-title"
}
},
plotOptions: {},
...this.state.ChartOne,
xaxis: {
width: 1,
...this.state.ChartOne.xaxis,
labels: {
show: false,
...this.state.ChartOne.xaxis.labels,
style: {
...this.state.ChartOne.xaxis.labels.style
}
},
categories: pageviewLocation
},
yaxis: {
min: 0,
...this.state.ChartOne.yaxis,
labels: {
//show: false,
...this.state.ChartOne.yaxis.labels,
style: {
...this.state.ChartOne.yaxis.labels.style
}
}
}
},
ChartOneSeries: [
{
name: "Total Page Views",
data: pageviewCount
}
]
});
}
componentDidUpdate(prevProps, prevState) {
if (this.state.filterstartDate === "" && this.state.filterendDate === "") {
console.log("they are empty");
} else {
this.setState({
// this fails immediately once the condition is met
test: "success!"
});
}
}
Datepicker = async (event, picker) => {
this.setState({
filterstartDate: moment(picker.startDate._d).format("YYYY-MM-DD"),
filterendDate: moment(picker.endDate._d).format("YYYY-MM-DD")
});
//console.log(this.state);
};
//or the error if there is one
handleError(reason) {
console.error(reason);
console.error(reason.result.error.message);
}
render() {
//console.log();
return (
<div className="containerfluid" id="fullWidth">
<Header />
<div className="container" id="chartContainer">
<h1>Site Analytics</h1>
<div className="row">
<div className="col-md-12">
<DateRangePicker
startDate={moment().format("MM-DD-YYYY")}
endDate={moment().format("MM-DD-YYYY")}
onApply={this.Datepicker}
>
<button className="btn btn-info">
<i className="fas fa-filter">
<span
style={{
fontFamily: "Roboto, san-serif",
fontWeight: "normal",
padding: "5px"
}}
>
Filter Date
</span>
</i>
</button>
</DateRangePicker>
</div>
</div>
<div className="row">
<div className="col-md-4">
{/* Chart One Line */}
{this.state.loading ? (
<React.Fragment>
<i className="fas fa-spinner fa-3x" id="loader" /> Please wait
...!
</React.Fragment>
) : (
<div className="chartContainer">
<Chart
options={this.state.ChartOne}
series={this.state.ChartOneSeries}
type="line"
width={400}
height={300}
/>
</div>
)}
</div>
</div>
<div id="my-signin2" />
</div>
<Footer />
</div>
);
}
}
export default Charts;
When you use setState you're triggering the lifecycle again. If you don't set your filterstartDate and filterendDate to "", you'll keep calling setState infinitely.
componentDidUpdate(prevProps, prevState) {
if (this.state.filterstartDate === "" && this.state.filterendDate === "") {
console.log("they are empty");
} else {
this.setState({
filterstartDate: "",
filterendDate: "",
test: "success!"
});
}
}

Google chart in angularjs ng-repeat

I am new to AngularJs and Google charts. My requirement is to show Google charts dynamically in ng-repeat for each li.
<li ng-repeat="ques in surveyquestions">
<label for="{{ques['questions']}}">
{{ques['id']}} {{ques['questions']}}
</label>
<div ng-init="calltry(ques['option_array'],ques['id'])"></div>
<div id="chartdiv{{ques['id']}}"></div>
</li>
In above code through ng-init I pass the data to render the Google chart. In JavaScript I used as below but it's not working.
var chart = new google.visualization.ColumnChart(document.getElementById('chartdiv'+id));
It's working fine when id is static like below.
<div id="chartdiv"></div>
var chart = new google.visualization.ColumnChart(document.getElementById('chartdiv'));
Please help to sort out what is the issue.
Try with angular-google-chart,
Refer :https://angular-google-chart.github.io/angular-google-chart/docs/latest/examples/bar/
<div class="chartContainer" ng-repeat="data in arrayDiv">
<div layout-padding layout-margin google-chart chart="drawChart(data)">
</div>
</div>
$scope.drawChart = function (value) {
$scope.chartData = [];
var chartValue = {
c: [{
v: 'subject
}, {
v: 5,
f: " questions"
}, {
v: 6,
f: " questions"
}]
};
$scope.chartData.push(chartValue);
$scope.qaChart = {};
$scope.qaChart.type = "BarChart";
$scope.qaChart.data = {
"cols": [{
id: "Sections",
label: "Subject",
type: "string"
}, {
id: "Correct",
label: "Correct",
type: "number"
}, {
id: "Wrong",
label: "Wrong",
type: "number"
}],
"rows": $scope.chartData
};
$scope.qaChart.options = {
"isStacked": "true",
"fill": 20,
"displayExactValues": true,
"colors": ['#4CAF50', '#EF5350', '#00adee'],
"vAxis": {
"title": " Questions",
},
"hAxis": {
"title": "Details",
}
};
return $scope.qaChart;
};

Angular formly - assign key to property in array

I am working on list of languages and levels of proficiency. This would be a array of objects:
languages : [
{ name : 'English', level : 'native' },
{ name : 'Spanish', level : 'good' }
]
So I have such definitions of fields:
{
className : 'col-xs-4',
type : 'ui-select',
key : 'languages[' + index + '].name',
templateOptions : {
label : 'Some label',
options : [ ... data there ... ],
required : true
}
},
{
className : 'col-xs-8 btn-radio-language',
type : 'btn-radio',
key : 'languages[' + index + '].level',
templateOptions : {
label : 'Proficiency',
options : ... data for native, good, so so ...
}
}
Those definition would repeat several times with respect of index.
However instead of array languages being addressed with values series of properties in model like:
"languages[0].level": "native",
"languages[1].level": "advanced",
"languages[0].name": "German"
have been created...
How I can point to languages array in model ?
If I've understood it correctly you could map your data with languages.map(function(language) {...}).
Please have a look at the demo below or at this jsfiddle.
angular.module('demoApp', ['formly', 'formlyBootstrap'])
.controller('MainController', function() {
var vm = this;
vm.model = {};
var languages = [
{ name : 'English', level : 'native' },
{ name : 'Spanish', level : 'good' }
];
var createOptionTmpl = function(value) {
return {
name: value,
value: value
};
};
/*
console.log(languages.map(function(lang) {
return {
name: lang.level,
value: lang.level
};
}));*/
vm.fields = [{
className: 'col-xs-4',
type: 'select',
key: 'languages.name',
templateOptions: {
label: 'Some label',
options: languages.map(function(lang) {
return createOptionTmpl(lang.name);
}), //[...data there...],
required: true
}
}, {
className: 'col-xs-8 btn-radio-language',
type: 'radio',
key: 'languages.level',
templateOptions: {
label: 'Proficiency',
options: languages.map(function(lang) {
return createOptionTmpl(lang.level);
})
}
}];
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/api-check/7.5.5/api-check.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-formly/7.3.9/formly.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-formly-templates-bootstrap/6.2.0/angular-formly-templates-bootstrap.min.js"></script>
<div ng-app="demoApp" ng-controller="MainController as vm">
<form ng-submit="vm.onSubmit()">
<formly-form model="vm.model" fields="vm.fields"></formly-form>
<button class="btn btn-primary">
submit
</button>
</form>
{{vm.model}}
</div>

KendoUI Grid does not invoke update function in popup mode with editable template

I'm using a Kendo UI Grid with AngularJS. The grid has a 'popup' mode editable kendo template. The grid invokes the create, destroy & delete functions; however the update function won't get called. Strangely when I change the edit mode to 'inline', the update function is called. Below are the code snippets from my application :
Main UI Grid:
<div class="container-fluid">
<kendo-grid style="margin-top: 2em" k-options="ctrl.fundGridOptions" k-scope-field="kgrid" id="myGrid"></kendo-grid>
</div>
Edit Template:
<script id="edit-template" type="text/x-kendo-template">
<div class="container">
<div class="well">
Fund :
<select kendo-drop-down-list k-options="ctrl.fundOptions" style="width: 130px;" ng-model="dataItem.GenevaId"></select>
<!--<select kendo-drop-down-list k-data-source="ctrl.funds" style="width: 130px;" ng-model="dataItem.GenevaId"></select>-->
NAV Change Threshold
<input kendo-numeric-text-box k-min="0" k-max="100" k-ng-model="value" style="width: 60px;" ng-model="dataItem.NAVThreshold" />
NAV Source
<select k-data-source="ctrl.navSources" kendo-drop-down-list k-option-label="'-Select-'" style="width: 130px;" ng-model="dataItem.NAVSource"></select>
Frequency
<select k-data-source="ctrl.frequencyList" kendo-drop-down-list k-option-label="'-Select-'" style="width: 130px;" ng-model="dataItem.Frequency"></select>
Type
<select k-data-source="ctrl.typeList" kendo-drop-down-list k-option-label="'-Select-'" style="width: 130px;" ng-model="dataItem.Type"></select>
</div>
<div kendo-grid="ctrl.currencyKendoGrid" style="margin-top: 2em" k-options="ctrl.currencyGridOptions"></div>
</div>
</script>
Grid Options:
ctrl.fundGridOptions = {
dataSource: {
transport: {
update: function (options) {
DataSvc.updateFund(e.data).then(function (response) {
e.success(e.data);
});
},
},
schema: {
model: {
id: "FundId",
fields: {
FundId: { type: "number", editable: false, nullable: true },
GenevaId: { type: "string", editable: true },
NAVThreshold: { type: "number", editable: true },
NAVSource: { type: "string", editable: true },
Frequency: { type: "string", editable: true },
Type: { type: "string", editable: true },
}
}
},
},
sortable: true,
columns: [
{ field: "GenevaId", title: "Fund Name" },
{ field: "NAVThreshold*100", title: "NAV Threshold", template: '#=kendo.format("{0:p}", NAVThreshold)#' },
{ field: "NAVSource", title: "NAV Source" },
{ field: "Frequency", title: "Frequency" },
{ field: "Type", title: "Type" },
{ command: ["edit", "destroy"], title: " " }
],
detailTemplate: kendo.template($("#detail-template").html()),
detailInit: function (e) {
kendo.bind(e.detailRow, e.data);
},
dataBound: function (e) {
var grid = e.sender;
if (grid.dataSource.total() == 0) {
var colCount = grid.columns.length;
$(e.sender.wrapper)
.find('tbody')
.append('<tr class="kendo-data-row"><td colspan="' + colCount + '" class="no-data">Sorry, no data :(</td></tr>');
}
},
editable: {
mode: "popup",
template: kendo.template($("#edit-template").html()),
window: {
title: "Edit Fund Details",
animation: false,
height: "600",
width: "1200"
}
},
edit: function (e) {
if (e.model.Currencies)
ctrl.currencyKendoGrid.dataSource.data(e.model.Currencies);
},
toolbar: [
{
name: 'create',
text: 'Add Fund',
}],
};
Could anyone help me understand the reason why the 'update' function won't be called in 'popup' mode, but gets called in 'inline' mode ? Appreciate any responses in advance.
I know this is question old, but I came across it searching for an answer. I think the issue might be that your (and my) edit template uses ng-model binding to edit the dataItem ie we're using angularjs. This doesn't actually seem to change the dirty property on the dataItem. I solved the issue by using ng-change on each control. It's a pain, but seems to work.
<input id="Title" type="text" class="k-textbox" ng-model="dataItem.Title" ng-change="dataItem.dirty=true"/>

Resources