Why is the action type unknown, and what is the fix?
I know this is a common problem. I searched SO and there are ~20 answers, many of which are related to mapActions. After reading thru most all of those answers, and trying countless variations of mapActions syntax, I still can't figure out what's wrong with my code.
I understand, we are supposed to call dispatch in the component (or module), which then commits a mutation in the Vuex store (which is where the actual value gets changed).
Also, not sure if it's helpful to point out, but I expected to see the actions and mutations in the state pic below, but do not.
Update:
After editeding the code as a couple others suggested, the result is still the same; unknown action type: toggleIsCategoryWheelSpinning,{}
Not sure if it's relevant, but the line where dispatch is called myStore.dispatch("toggleIsCategoryWheelSpinning,{}"); in Wheel.vue is inside a nested function.
Here is my code:
//Wheel.vue
<template>
<div >
<div id="chart"></div>
</div>
</template>
<script type="text/javascript" charset="utf-8">
import store from 'vuex'
import { mapActions} from 'vuex'
export default {
name: "wheel",
props: {
wheelCategories: {
type: Array,
required: true,
},
expressions: {
type: Array,
required: true,
},
},
data() {
return {
};
},
mounted() {
let myscript = document.createElement("script");
myscript.setAttribute("src", "https://d3js.org/d3.v3.min.js");
document.head.appendChild(myscript);
myscript.onload = this.createWheel(this.wheelCategories,this.expressions, this.$store);
},
methods: {
...mapActions(['toggleIsCategoryWheelSpinning']),
created(){
this.toggleIsCategoryWheelSpinning
},
createWheel: function (wheelCategories,expressions, myStore) {
var padding = { top: 20, right: 40, bottom: 20, left: 20 },
w = 500 - padding.left - padding.right,
h = 500 - padding.top - padding.bottom,
r = Math.min(w, h) / 2,
rotation = 0,
oldrotation = 0,
picked = 100000,
oldpick = [],
color = d3.scale.category20();
var svg = d3
.select("#chart")
.append("svg")
.data([wheelCategories])
.attr("width", w + padding.left + padding.right)
.attr("height", h + padding.top + padding.bottom);
var container = svg
.append("g")
.attr("class", "chartholder")
.attr(
"transform",
"translate(" +
(w / 2 + padding.left) +
"," +
(h / 2 + padding.top) +
")"
)
.style({ cursor: "grab" });
var vis = container.append("g");
var pie = d3.layout
.pie()
.sort(null)
.value(function (d) {
return 1;
});
var arc = d3.svg.arc().outerRadius(r);
var arcs = vis
.selectAll("g.slice")
.data(pie)
.enter()
.append("g")
.attr("class", "slice");
arcs.append("path")
.attr("fill", function (d, i) {
return color(i);
})
.attr("d", function (d) {
return arc(d);
});
// add the text
arcs.append("text").attr("transform", function (d) {
d.innerRadius = 0;
d.outerRadius = r;
d.angle = (d.startAngle + d.endAngle) / 2;
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")translate(" + (d.outerRadius -10) +")";
})
.attr("text-anchor", "end")
.text(function (d, i) {
return wheelCategories[i].label;
});
container.on("click", spin);
function spin(d) {
container.on("click", null);
//the following line gives the "unknown action"
myStore.dispatch("toggleIsCategoryWheelSpinning,{}");
console.log('dispatch finished');
//all slices have been seen, all done
if (oldpick.length == wheelCategories.length) {
document.getElementById("spinResponse"
).innerHTML = `out of spins`;
container.on("click", null);
return;
}
var ps = 360 / wheelCategories.length,
pieslice = Math.round(1440 / wheelCategories.length),
rng = Math.floor(Math.random() * 1440 + 360);
rotation = Math.round(rng / ps) * ps;
picked = Math.round(
wheelCategories.length - (rotation % 360) / ps
);
picked =
picked >= wheelCategories.length
? picked % wheelCategories.length
: picked;
if (oldpick.indexOf(picked) !== -1) {
d3.select(this).call(spin);
return;
} else {
oldpick.push(picked);
}
rotation += 90 - Math.round(ps / 2);
let index = Math.floor(Math.random() * expressions.length); // 10 returns a random integer from 0 to 9
vis.transition()
.duration(3000)
.attrTween("transform", rotTween)
.each("end", function () {
oldrotation = rotation;
container.on("click", spin);
});
}
//make arrow
svg.append("g")
.attr(
"transform",
"translate(" +
(w + padding.left + padding.right) +
"," +
(h / 2 + padding.top) +
")"
)
.append("path")
.attr(
"d",
"M-" +
r * 0.15 +
",0L0," +
r * 0.05 +
"L0,-" +
r * 0.05 +
"Z"
)
.style({ fill: "black" });
//draw spin circle
container
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 60)
.style({ fill: "white", cursor: "grab" });
//spin text
container
.append("text")
.attr("x", 0)
.attr("y", 15)
.attr("text-anchor", "middle")
.text("SPIN ME!")
.style({
"font-weight": "bold",
"font-size": "25px",
cursor: "grab",
});
function rotTween(to) {
var i = d3.interpolate(oldrotation % 360, rotation);
return function (t) {
return "rotate(" + i(t) + ")";
};
}
function getRandomNumbers() {
var array = new Uint16Array(1000);
var scale = d3.scale
.linear()
.range([360, 1440])
.domain([0, 100000]);
if (
window.hasOwnProperty("crypto") &&
typeof window.crypto.getRandomValues === "function"
) {
window.crypto.getRandomValues(array);
console.log("works");
} else {
//no support for crypto, get crappy random numbers
for (var i = 0; i < 1000; i++) {
array[i] = Math.floor(Math.random() * 100000) + 1;
}
}
return array;
}
}
}
};
//end code for wheel
</script>
<style type="text/css" scoped>
text {
font-size: 15px;
pointer-events: grab;
}
#chart {
/* cursor: grab; */
margin: 0 auto;
border: 10px;
}
#question {
text-align: center;
}
#question h1 {
font-size: 50px;
font-weight: bold;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
/* position: absolute; */
padding: 0;
margin: 0;
top: 50%;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
}
#spinResponse {
font-size: 30px;
text-align: center;
width: 500px;
padding-bottom: 30px;
background-color: rgb(129, 19, 19);
font-weight: bold;
}
</style>
the vuex store
// store/index.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const foodCategories = [
//...
];
const expressions = [
//...
];
const isCategoryWheelSpinning = false;
export default new Vuex.Store({
state: {
foodCategories,
expressions,
isCategoryWheelSpinning,
},
getters: {
},
actions: {
toggleIsCategoryWheelSpinning(context,payload){
context.commit("toggleIsCategoryWheelSpinning",payload);
}
},
mutations: {
toggleIsCategoryWheelSpinning(state, payload) {
state.isCategoryWheelSpinning = !isCategoryWheelSpinning;
},
},
});
and the main.js
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store';
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
your action name mismatches. It should be same for your code.
Try to use :...mapActions(["toggleIsCategoryWheelSpinning"] for importing the action
In your actions in the store, there is no action called action_toggleIsCategoryWheelSpinning, but there is one called toggleIsCategoryWheelSpinning, so in your mapActions you should import that:
methods: {
mapActions(['toggleIsCategoryWheelSpinning'])
}
The comment from #Tao (see below) lead to (is) the answer; specifically the bold text.
The following code edits fixed the problem.
In Wheel.vue, edit the methods section
...mapActions(['toggleIsCategoryWheelSpinning']),
created(){
this.toggleIsCategoryWheelSpinning
},
When dispatch is called, changed from the first line to the second.
myStore.dispatch("toggleIsCategoryWheelSpinning,{}");
myStore.dispatch("toggleIsCategoryWheelSpinning",{});
An action is called with two parameters: name, which is a string in
the form of {module/}{action} (with module names when you're using
modules) and payload, which can be an object (or array, which is still
an object) or any primitive (string, boolean, number, etc...). So call
it as dispatch("toggleIsCategoryWheelSpinning", {}) if you want to
call it with an empty object as payload. You've placed the payload
inside the name parameter and it results into a string which doesn't
map onto a known action. – tao 30 mins ago
I'm working with vue-typer and it adjusts on screen according to the space. But, depending the size of the screen, the vue-typer breaks the word. I want to break just when we have backspace. The code is:
<vue-typer
class="text-h4 font-weight-bold"
text="Nós acreditamos que o futuro pode ser incrível. Quer criar
ele com a gente?" :repeat='0'
></vue-typer><br>
Here is the image of how is working now
I dont know if anyone is still dealing with this issue, I have written a quick fix to the issue. Its not perfect but does the job.
You will run the text through a Method that will auto add in the line breaks automatically.
<div
style="
font-size: 30pt;
margin: auto;
color: white;
max-width: 600px;
"
ref="theRef"
>
<vue-typer
v-if="startTypers"
:text="[
formatText(
'TextHere',
'theRef',
22
),
]"
:repeat="0"
:shuffle="false"
initial-action="typing"
:pre-type-delay="70"
:type-delay="70"
:pre-erase-delay="2000"
:erase-delay="100"
erase-style="backspace"
:erase-on-complete="false"
caret-animation="blink"
></vue-typer>
</div>
mounted() {
setTimeout(() => {
this.startTypers = true;
}, 150);
}
The reason for the startTypers is because they will run the formatText method before the div has been rendered. Meaning you won't be able to get the clientWidth of the parent div.
formatText(text, ref, textSize = 22) {
let maxChars = Math.floor(this.$refs[ref].clientWidth / textSize);
let words = text.split(" ");
let breaked = "";
let currentCount = 0;
words.forEach((word) => {
currentCount += word.length;
currentCount += 1;
if (currentCount >= maxChars) {
currentCount = word.length;
breaked = `${breaked}\n${word} `;
} else {
breaked = `${breaked}${word} `;
}
});
return breaked;
},
The Parameters for formatText are the Text that you want to have the line breaks added in, The name of the ref, and the size of the span(Chars) that is rendered (22 was the default for the font and font-size I used in my use case, yours will vary)
Hopefully this helps
In order to break the text into chunks, consider the following
data() {
text : 'Hello World! I`m clarification masterjam!',
},
computed : {
textComputed() {
let n = "\n"
let breaked = this.text.match(/.{1,25}/g);
breaked[0];
var pos = breaked[0].lastIndexOf(' ');
breaked[0] = breaked[0].substring(0,pos)+n+breaked[0].substring(pos+1);
return breaked.join('')
},
}
I am trying to put grid(developed with scrollview) inside scrollview but I can't set grid height with content height. I can't handle this problem with .fixedsize()
GeometryReader{ reader in
ScrollView{
Text(reader.size.height.description)
Text(reader.size.height.description)
FlowStack(columns: 3, numItems: 27, alignment: .leading) { index, colWidth in
if index == 0{
Text(" \(index) ").frame(width: colWidth).border(Color.gray)
.background(Color.red)
}
else if index == 1{
Text(" \(index) ").frame(width: colWidth).border(Color.gray)
}
else if index == 2{
Text(" \(index) ").frame(width: colWidth).border(Color.gray)
}
else{
Text(" \(index) ").frame(width: colWidth).border(Color.gray)
}
}
.background(Color.red)
Text(reader.size.height.description)
Text(reader.size.height.description)
}.fixedSize(horizontal: false, vertical: false)
}
Result
What I want
I don't know what did you wrote in FlowStack struct, that's why it's really hard to give right answer. There is how I solve this grid:
struct GridScrollView: View {
var body: some View {
GeometryReader{ geometry in
VStack {
Text("height: \(geometry.size.height.description)")
Text("width: \(geometry.size.width.description)")
ScrollView{
FlowStack(columns: 3, numItems: 60, width: geometry.size.width, height: geometry.size.height)
}
}
}
}
}
my FlowStack code:
struct FlowStack: View {
var columns: Int
var numItems: Int
var width: CGFloat
var height: CGFloat
private var numberOfRows: Int {
get {
numItems / columns
}
}
private var cellWidth: CGFloat {
get {
width / CGFloat(columns) - 4 // with padding
}
}
private var cellHeight: CGFloat {
get {
height / CGFloat(numberOfRows) - 4 // with padding
}
}
var body: some View {
ForEach(0..<self.numberOfRows, id: \.self) { row in
HStack {
ForEach(1...self.columns, id: \.self) { col in
Text("\(row * self.columns + col)")
.frame(width: self.cellWidth, height: self.cellHeight, alignment: .center)
.background(Color.red)
.border(Color.gray)
.padding(2)
}
}
}
}
}
and the result is:
P.S. that's my quick solution. I think you can also use this grid from github, it's quite massive, but flexible in my opinion
I'm trying out the aurelia-interactjs plugin to see if it meets my needs. I installed it into a new aurelia cli project by following all of the installation steps. I then added code for the Dragging section of the interactjs demo. The browser console displays the following error stating that interact is not a function:
Unhandled rejection TypeError: interact is not a function. (In 'interact(this.element)', 'interact' is undefined)
attached#http://localhost:9005/node_modules/aurelia-interactjs/dist/amd/interact-draggable.js:18:21
Here's my code:
app.html
<template>
<div id="drag-1" interact-draggable.bind="interactjsOptions">
<p> You can drag one element </p>
</div>
<div id="drag-2" interact-draggable.bind="interactjsOptions">
<p> with each pointer </p>
</div>
</template>
app.js
export class App {
constructor() {
this.interactjsOptions = {
// enable inertial throwing
inertia: true,
// keep the element within the area of it's parent
restrict: {
restriction: "parent",
endOnly: true,
elementRect: {
top: 0,
left: 0,
bottom: 1,
right: 1
}
},
// enable autoScroll
autoScroll: true,
// call this function on every dragmove event
onmove: dragMoveListener,
// call this function on every dragend event
onend: function(event) {
var textEl = event.target.querySelector('p');
textEl && (textEl.textContent =
'moved a distance of ' +
(Math.sqrt(event.dx * event.dx +
event.dy * event.dy) | 0) + 'px');
}
};
}
}
function dragMoveListener(event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
I am sorry, wrote the above in the bus on my commute to work on my phone didn't read all the code :-)
If you want to have the basic draggable sample (first one from http://interactjs.io/), which allows you to just drag elements around:
app.css
.draggable {
width: 25%;
height: 100%;
min-height: 6.5em;
margin: 10%;
background-color: #29e;
color: white;
border-radius: 0.75em;
padding: 4%;
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
}
app.html
<template>
<require from="app.css"></require>
<div
interact-draggable.bind="interactOptions"
interact-dragend.delegate="dragEnd($event)"
interact-dragmove.delegate="dragMoveListener($event)"
class="draggable">
<p> You can drag one element </p>
</div>
<div
interact-draggable.bind="interactOptions"
interact-dragend.delegate="dragEnd($event)"
interact-dragmove.delegate="dragMoveListener($event)"
class="draggable">
<p> with each pointer </p>
</div>
</template>
app.ts (if you remove the public keyword in the function it will be valid js I think)
export class App {
public dragMoveListener(event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.detail.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.detail.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}
public dragEnd(event) {
var textEl = event.target.querySelector('p');
textEl && (textEl.textContent =
'moved a distance of '
+ (Math.sqrt(event.detail.dx * event.detail.dx +
event.detail.dy * event.detail.dy)|0) + 'px');
}
public interactOptions = {
// enable inertial throwing
inertia: true,
// keep the element within the area of it's parent
restrict: {
restriction: "parent",
endOnly: true,
elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
},
// enable autoScroll
autoScroll: true,
};
}
I am loading multiple DIV from Database
That my Javascript for click
<script type="text/javascript">
$(document).ready( function() {
var role = 0;
$(".role").click(function(){
if(role == 0)
{
role = 1;
$(".role").text("Decision Approver");
}
else if(role == 1)
{
role = 2;
$(".role").text("Decision Maker");
}
else if(role == 2)
{
role = 3;
$(".role").text("Influencer");
}
else if(role == 3)
{
role = 4;
$(".role").text("Gate Keeper");
}
else if(role == 4)
{
role = 5;
$(".role").text("User");
}
else if(role == 5)
{
role = 6;
$(".role").text("Stake-holder");
}
else if(role == 6)
{
role = 0;
$(".role").text("");
}
});
});
</script>
my CSS for the DIV "role"
{
position: absolute;
width: 50px;
min-height:20px;
height:auto;
border:1px solid #000;
word-wrap: break-word;
float:left;
font-size:12px;
z-index: 30;
margin-top:50px;
margin-left:3px;
}
This is the HTML
$qry = "SELECT * from contact";
$result = mysql_query($qry);
while ($row = mysql_fetch_array($result))
{
<div class="role" align="center" ></div>
}
Multiple DIV has been generated, when I click on one DIV role, all the DIV role change their text. How can I change each DIV individually and update them to database by contactID?
Assuming you want to use jQuery to do this client-side (and on this assumption I've no idea what the SQL is doing in either the tags or the question) I'd suggest using an array to contain the new text:
var textValues = ['Decision maker', 'Decision approver', 'influencer']; // and so forth
$('.role').text(function(i){
return textValues[i];
});
JS Fiddle demo.
The above will iterate over each of the .role elements, the i represents the index of the current element (amongst those other elements in the collection), and will set the text to that contained at the i position within the textValues array.
References:
text().
I think when you are updating the role, all conditions are met one after the other, so you need to include return false; that is similar to break;