I am generating dynamic array and passing it to react-select default Value attribute but failing to do so. Here is my code:
//enter code here
if (this.state.campaignDetail && this.state.campaignDetail.length) {
var str = this.state.campaignDetail[0].jobLevel;
var str_array = str.split(',');
for (var i = 0; i < str_array.length; i++) {
jobLevelArray.push({ 'value': str_array[i], 'label': str_array[i] });
} this.setState({ jobLevelArray1:jobLevelArray });
alert(JSON.stringify(jobLevelArray));
}
//enter code here
<Select
value={this.state.jobLevelArray1}
//defaultValue={this.state.jobLevelArray1}
isMulti
onChange={this.jobLevelhandleChange}
options={this.state.jobLevelOptions} className="basic-multi-select" classNamePrefix="select" />
Related
I need help,
Requirement
when the user types in an input box I want to highlight the link with blue color if any
My Research
when I dig into it, I realize that without using a contenteditable div it's not possible to do, also there is no v-model associated with contenteditable div I am manually updating the state.
so far I have this, courtesy- contenteditable div append a html element and v-model it in Vuejs
<div id="app"><div class="flex">
<div class="message" #input="updateHtml" v-html="html" contenteditable="true"></div>
<br>
<div class="message">{{ html }}</div>
</div>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
html: 'some text',
},
methods: {
updateHtml: function(e) {
this.html = e.target.innerHTML;
},
renderHtml: function(){
this.html += '<img src="https://cdn-images-1.medium.com/max/853/1*FH12a2fX61aHOn39pff9vA.jpeg" alt="" width=200px>';
}
}
});</script>
Issue
every time user types something, the focus is misbehaving which is strange to me, I want v-html to update along with user types #keyup,#keydown also have the same behavior.it works ok on #blur #focusout events, but that's not what I want
Appreciate Help.Thanks
I figured it out myself. Posting the answer so that may help other developers. v-HTML doesn't do all the trick. You’ll need to store the cursor position so it can be restored properly each time the content updates as well as parse the content so that it renders as expected. Here is the example
HTML
<p>
An example of live syntax highlighting in a content-editable element. The hard part is storing and restoring selection after changing the DOM to account for highlighting.
<p>
<div contentEditable='true' id='editor'>
Edit text here. Try some words like bold and red
</div>
<p>
Just a demo trivial syntax highlighter, should work with any syntax highlighting you want to implement.
</p>
JS
const editor = document.getElementById('editor');
const selectionOutput = document.getElementById('selection');
function getTextSegments(element) {
const textSegments = [];
Array.from(element.childNodes).forEach((node) => {
switch(node.nodeType) {
case Node.TEXT_NODE:
textSegments.push({text: node.nodeValue, node});
break;
case Node.ELEMENT_NODE:
textSegments.splice(textSegments.length, 0, ...(getTextSegments(node)));
break;
default:
throw new Error(`Unexpected node type: ${node.nodeType}`);
}
});
return textSegments;
}
editor.addEventListener('input', updateEditor);
function updateEditor() {
const sel = window.getSelection();
const textSegments = getTextSegments(editor);
const textContent = textSegments.map(({text}) => text).join('');
let anchorIndex = null;
let focusIndex = null;
let currentIndex = 0;
textSegments.forEach(({text, node}) => {
if (node === sel.anchorNode) {
anchorIndex = currentIndex + sel.anchorOffset;
}
if (node === sel.focusNode) {
focusIndex = currentIndex + sel.focusOffset;
}
currentIndex += text.length;
});
editor.innerHTML = renderText(textContent);
restoreSelection(anchorIndex, focusIndex);
}
function restoreSelection(absoluteAnchorIndex, absoluteFocusIndex) {
const sel = window.getSelection();
const textSegments = getTextSegments(editor);
let anchorNode = editor;
let anchorIndex = 0;
let focusNode = editor;
let focusIndex = 0;
let currentIndex = 0;
textSegments.forEach(({text, node}) => {
const startIndexOfNode = currentIndex;
const endIndexOfNode = startIndexOfNode + text.length;
if (startIndexOfNode <= absoluteAnchorIndex && absoluteAnchorIndex <= endIndexOfNode) {
anchorNode = node;
anchorIndex = absoluteAnchorIndex - startIndexOfNode;
}
if (startIndexOfNode <= absoluteFocusIndex && absoluteFocusIndex <= endIndexOfNode) {
focusNode = node;
focusIndex = absoluteFocusIndex - startIndexOfNode;
}
currentIndex += text.length;
});
sel.setBaseAndExtent(anchorNode,anchorIndex,focusNode,focusIndex);
}
function renderText(text) {
const words = text.split(/(\s+)/);
const output = words.map((word) => {
if (word === 'bold') {
return `<strong>${word}</strong>`;
}
else if (word === 'red') {
return `<span style='color:red'>${word}</span>`;
}
else {
return word;
}
})
return output.join('');
}
updateEditor();
Hope this helps...
In a project which I am doing there is a part which involves rendering images taken from the database. One image is rendered without a problem, but when I try to incrementally render all the rows from the database, there starts to be a problem:
main.component.ts
homeDetails() {
this.info.getHomeDetails().subscribe(
gethomedetails => {
this.id = gethomedetails[0].id;
this.picByte = gethomedetails[0].picByte;
// for ( let i=0; i<=gethomedetails.length; i++) {
// this.id = homedetails[0].id;
this.picByte = gethomedetails[i].picByte;
this.id = gethomedetails[i].id;
console.log("id" + this.id);
// this.picByte = homedetails[i].picByte;
// }
this.retrievedImage = 'data:image/jpeg;base64,' + this.picByte;
// }
console.log("retrievedimage" + this.retrievedImage);
// for (let i=0; i<=this.id; i++) {
// console.log("id" + i);
// }
// for (let i=0; i<=this.id; i++) {
// this.picByte = homedetails[i].picByte;
// this.retrievedImage = 'data:image/jpeg;base64,' + this.picByte;
// console.log("retrievedimage" + this.retrievedImage);
// }
// this.images = homedetails
}
)
// return this.domSanitizer.bypassSecurityTrustResourceUrl(this.retrievedImage);
}
main.component.html
<img [src]="retrievedImage"> works just for one file
Could you please point me out how I should do it?
Thank you.
You could do this in a simple manner:
homeDetails() {
this.info
.getHomeDetails()
.subscribe(data =>
this.images = data.map(data => (
{
id: data.id,
src: 'data:image/jpeg;base64,' + data.picByte
}
)
)
}
And then in the HTML
<div *ngFor="let image of images">
<img [src]="image.src">
</div>
i would like to use a js query code that I found on codepen in my vue project, but im not sure How to integrate it .
I simply pasted the file in my created() of my vue component but it doesn seem to work out.. the code is supposing to run a visual animation when typing chinese caractere in the input form.
this is the codepen : https://codepen.io/simeydotme/pen/CFcke
var $input = $('input');
$input.on({
"focus": function(e) {
$(".input-container").addClass("active");
},
"blur": function(e) {
$(".input-container").removeClass("active");
}
});
var previous = null;
setInterval( function() {
if( previous !== $input.val()
|| "" === $input.val()) {
getGoodCharacters( $input );
previous = $input.val();
}
}, 500);
function getGoodCharacters( $this ) {
var output = $this.val().trim();
var letters = output.split("");
var url = "https://service.goodcharacters.com/images/han/$$$.gif";
$(".error-container, .help").removeClass("show");
$(".output-container").empty();
for( letter in letters ) {
var img = letters[letter] + "";
var newurl = url.replace("$$$",img);
loadCharacter( newurl , img );
}
}
function loadCharacter( url , letter ) {
var img = new Image();
var $output = $(".output-container");
var $a = $("<a/>");
var l = $("input").val().length;
var cwidth = "120px";
if( l > 7 ) { cwidth = "70px"; }
else if( l > 6 ) { cwidth = "90px"; }
else if( l > 5 ) { cwidth = "100px"; }
$(img).load(function(){
$a.attr({
"href": url,
"title": "Good Character Chinese Symbol: "+ letter + ""
}).css("width", cwidth ).append( $(this) ).appendTo($output);
$(".help").addClass("show");
}).attr({
src: url
}).error(function(){
$(".error-container").addClass("show");
});
}
var $try = $(".tryme a").on("click", function(e) {
e.preventDefault();
$input.val( $(this).text() );
});
I also imported the jquery module in my componant
import $ from "jquery";
here is the html that i added in the template
<div class="container input-container">
<input type="text" id="input" placeholder="中文" value="中文"/>
</div>
Thanks!
i'm trying re-organised a list of data. I have given each li a unique key, but still, no luck!
I have had this working before exactly like below, think i'm cracking up!
let app = new Vue({
el: '#app',
data: {
list: [
{ value: 'item 1', id: '43234r' },
{ value: 'item 2', id: '32rsdf' },
{ value: 'item 3', id: 'fdsfsdf' },
{ value: 'item 4', id: 'sdfg543' }
]
},
methods: {
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in list" :key="item.id">{{ item.value }}</li>
</ul>
Randomize
</div>
Edit:
Thanks for the answers, to be honest the example I provided may not have been the best for my actual issue I was trying to solve. I think I may have found the cause of my issue.
I'm basically using a similar logic as above, except i'm moving an array of objects around based on drag and drop, this works fine with normal HTML.
However, i'm using my drag and drop component somewhere else, which contains ANOTHER component and this is where things seem to fall apart...
Would having a component within another component stop Vue from re-rendering when an item is moved within it's data?
Below is my DraggableBase component, which I extend from:
<script>
export default {
data: function() {
return {
dragStartClass: 'drag-start',
dragEnterClass: 'drag-enter',
activeIndex: null
}
},
methods: {
setClass: function(dragStatus) {
switch (dragStatus) {
case 0:
return null;
case 1:
return this.dragStartClass;
case 2:
return this.dragEnterClass;
case 3:
return this.dragStartClass + ' ' + this.dragEnterClass;
}
},
onDragStart: function(event, index) {
event.stopPropagation();
this.activeIndex = index;
this.data.data[index].dragCurrent = true;
this.data.data[index].dragStatus = 3;
},
onDragLeave: function(event, index) {
this.data.data[index].counter--;
if (this.data.data[index].counter !== 0) return;
if (this.data.data[index].dragStatus === 3) {
this.data.data[index].dragStatus = 1;
return;
}
this.data.data[index].dragStatus = 0;
},
onDragEnter: function(event, index) {
this.data.data[index].counter++;
if (this.data.data[index].dragCurrent) {
this.data.data[index].dragStatus = 3;
return;
}
this.data.data[index].dragStatus = 2;
},
onDragOver: function(event, index) {
if (event.preventDefault) {
event.preventDefault();
}
event.dataTransfer.dropEffect = 'move';
return false;
},
onDragEnd: function(event, index) {
this.data.data[index].dragStatus = 0;
this.data.data[index].dragCurrent = false;
},
onDrop: function(event, index) {
if (event.stopPropagation) {
event.stopPropagation();
}
if (this.activeIndex !== index) {
this.data.data = this.array_move(this.data.data, this.activeIndex, index);
}
for (let index in this.data.data) {
if (!this.data.data.hasOwnProperty(index)) continue;
this.data.data[index].dragStatus = 0;
this.data.data[index].counter = 0;
this.data.data[index].dragCurrent = false;
}
return false;
},
array_move: function(arr, old_index, new_index) {
if (new_index >= arr.length) {
let k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
}
}
}
</script>
Edit 2
Figured it out! Using the loop index worked fine before, however this doesn't appear to be the case this time!
I changed the v-bind:key to use the database ID and this solved the issue!
There are some Caveats with arrays
Due to limitations in JavaScript, Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
To overcome caveat 1, both of the following will accomplish the same as vm.items[indexOfItem] = newValue, but will also trigger state updates in the reactivity system:
Vue.set(vm.items, indexOfItem, newValue)
Or in your case
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
Vue.set(input, randomIndex, input[i]);
Vue.set(input, i, itemAtIndex);
}
this.list = input;
}
Here is an working example: Randomize items fiddle
Basically I changed the logic of your randomize function to this:
randomize() {
let new_list = []
const old_list = [...this.list] //we don't need to copy, but just to be sure for any future update
while (new_list.length < 4) {
const new_item = old_list[this.get_random_number()]
const exists = new_list.findIndex(item => item.id === new_item.id)
if (!~exists) { //if the new item does not exists in the new randomize list add it
new_list.push(new_item)
}
}
this.list = new_list //update the old list with the new one
},
get_random_number() { //returns a random number from 0 to 3
return Math.floor(Math.random() * 4)
}
randomise: function() { let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = this.list[randomIndex];
Vue.set(this.list,randomIndex,this.list[i])
this.list[randomIndex] = this.list[i];
this.list[i] = itemAtIndex;
} this.list = input;
}
Array change detection is a bit tricky in Vue. Most of the in place
array methods are working as expected (i.e. doing a splice in your
$data.names array would work), but assigining values directly (i.e.
$data.names[0] = 'Joe') would not update the reactively rendered
components. Depending on how you process the server side results you
might need to think about these options described in the in vue
documentation: Array Change Detection.
Some ideas to explore:
using the v-bind:key="some_id" to have better using the push to add
new elements using Vue.set(example1.items, indexOfItem, newValue)
(also mentioned by Artokun)
Source
Note that it works but im busy so i cant optimize it, but its a little bit too complicted, i Edit it further tomorrow.
Since Vue.js has some caveats detecting array modification as other answers to this question highlight, you can just make a shallow copy of array before randomazing it:
randomise: function() {
// make shallow copy
let input = this.list.map(function(item) {
return item;
});
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}
I'm trying to create dropdown list with names of TestSets. I need that for filtering purpose.
I have tried with below code:
function dropdownChanged(dropdown, eventArgs) {
var selectedItem = eventArgs.item;
var selectedValue = eventArgs.value;
}
function onLoad() {
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__');
var config = {
type : "testset",
attribute : "name"
};
var attributeDropdown = new rally.sdk.ui.AttributeDropdown(config, rallyDataSource);
attributeDropdown.display("aDiv", dropdownChanged);
}
rally.addOnLoad(onLoad);
Can anyone help me with that?
You may use Object Dropdown instead of Attribute Dropdown. In this code test set selection from the attribute dropdown results in a table populated with test cases of the selected test set.
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.32/sdk.js"></script>
<script type="text/javascript">
var table = null;
function showTable(results) {
var t = " ";
var tableConfig = {
columnKeys : ['Name','FormattedID','TestCases'],
columnHeaders : ['Name','FormattedID','TestCases'],
columnWidths : ['200px','200px', '400px']
};
table = new rally.sdk.ui.Table(tableConfig);
for (var i=0; i < results.ts.length; i++) {
if (results.ts[i].TestCases){
console.log(results.ts[i].TestCases.length);
for(var j = 0; j < results.ts[i].TestCases.length; j++){
// console.log(results.ts[i].TestCases.length);
// console.log(results.ts[i].TestCases[j].FormattedID);
t += " ";
t += results.ts[i].TestCases[j].FormattedID;
}
results.ts[i].TestCases=t;
}
table.addRows(results.ts);
table.display(document.getElementById('tableDiv'));
}
}
function dropdownChanged(dropdown, eventArgs) {
if(table) {
table.destroy();
}
document.getElementById('tableDiv').innerHTML = "";
var queryConfig = {
type : 'testset',
key : 'ts',
fetch: 'Name,FormattedID,TestCases',
query: '(Name = "' + eventArgs.item.Name + '")'
};
rallyDataSource.findAll(queryConfig, showTable);
}
function onLoad() {
rallyDataSource = new rally.sdk.data.RallyDataSource('111', //USE YOUR OIDs
'222',
'false',
'false');
var config = {
type : "testset",
attribute: "Name",
query : '(ScheduleState = "Defined")'
};
var objectDropdown = new rally.sdk.ui.ObjectDropdown(config, rallyDataSource);
objectDropdown.display("aDiv", dropdownChanged);
}
rally.addOnLoad(onLoad);
</script>
</head>
<body>
<div id="aDiv"></div>
<div id="tableDiv"></div>
</body>
</html>