I have added one more button in ngx-editor-menu for having emoji feature as well. But whenever I am adding emoji in text, it comes in new line. I am not able to find any way to add in the same line. In fact I want to make this editor as a input box in look wise, means no multiline.
I tried this
html
<form [formGroup]="form">
<div class="editor">
<ngx-editor [editor]="editor" formControlName="editorContent" name="myEditor" ngDefaultControl>
</ngx-editor>
<ngx-editor-menu
[editor]="editor"
[toolbar]="toolbar"
[customMenuRef]="customMenu"
>
</ngx-editor-menu>
</div>
</form>
<emoji-mart
(emojiClick)="addEmoji($event)"
*ngIf="showEmojiPicker"
emoji="point_up"
></emoji-mart>
<ng-template #customMenu>
<button (click)="toggleEmojiPicker()">emoji dropdown1</button>
</ng-template>
ts file
editor: Editor;
showEmojiPicker = false;
toolbar: Toolbar = [
['bold', 'italic'],
['text_color', 'background_color'],
['align_left', 'align_center', 'align_right', 'align_justify'],
];
emoji;
addEmoji($event) {
let data = this.emoji;
console.log('editorContent', this.form);
this.form.patchValue({editorContent: this.form.value.editorContent + $event.emoji.native});
}
toggleEmojiPicker() {
this.showEmojiPicker = !this.showEmojiPicker;
}
form = new FormGroup({
editorContent: new FormControl(
{ value: '', disabled: false },
Validators.required()
),
});
I tried to append it to current text using patchValue, but it creates new line. I want to add that emoji in same line.
Related
I'm creating a library app where users input data into a form and the values they enter are displayed in its own div.
I have this array
let myLibrary = [
{
title: "The Once and Future King",
author: "White",
pages: 654,
},
{
title: "The Hobbit",
author: "Tolkien",
pages: 304,
},
];
which is automatically displaying each object (for testing purposes) on my page thanks to this forEach()
myLibrary.forEach((book) => {
const bookContent = document.getElementById("content");
const addBook = document.createElement("div");
addBook.className = "book";
bookContent.appendChild(addBook);
addBook.innerHTML = `
<div class="title">
<p class="bookTitle">
<span>${book.title}</span>
</p>
</div>
<div class="body">
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>`;
});
The forEach makes it so every object inside my array is displayed in its own 280x365 pixel div and the book title, author and page count is displayed in it's own p element. I'm also using flex for organization.
I also have a form which users can input a new book title, author and page number to add to their growing book collection.
const form = document.getElementById("form");
form.addEventListener("submit", updateLibrary);
function updateLibrary(event) {
event.preventDefault();
const title = document.getElementById("title").value;
const author = document.getElementById("author").value;
const pages = document.getElementById("pages").value;
const book = {
title: title,
author: author,
pages: parseInt(pages),
};
myLibrary.push(book);
console.log(myLibrary);
}
When I fill the form out, everything appears to work perfectly. I have console.log in my updateLibrary function and I notice the object is being pushed into the array like I want it to. But every time I hit the submit button, a new div isn't being created for the new book. I'm guessing this has to do with my forEach not triggering the new object but I can't find a way to fix this.
How can I better write my code so a new div is also being created with the new object every time I submit the form?
What I've tried
I've tried rearranging my code so the forEach is below the array, so the updateLibrary function is above and below the forEach.
I've also tried putting the forEach inside the updateLibrary function. That did make it work but it gave me an even worse bug.
That is normal. The DOM (so the HTML within the page) is not automatically updated everytime that you change your array. If you want to work like this, I suggest you to look at ReactJS.
But to solve your problem, you must do 3 easy things here : create a function that will handle the display of your object in HTML, update your forEach to only call this new function, then, when a user create a new object, apply it this function :
const bookContent = document.getElementById("content");
function displayBook(book) {
const addBook = document.createElement("div");
addBook.className = "book";
bookContent.appendChild(addBook);
addBook.innerHTML = `
<div class="title">
<p class="bookTitle">
<span>${book.title}</span>
</p>
</div>
<div class="body">
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>`;
}
// Display your original object list
myLibrary.forEach((book) => {
displayBook(book)
});
// Handle your object creation
const form = document.getElementById("form");
form.addEventListener("submit", updateLibrary);
function updateLibrary(event) {
event.preventDefault();
const title = document.getElementById("title").value;
const author = document.getElementById("author").value;
const pages = document.getElementById("pages").value;
const book = {
title: title,
author: author,
pages: parseInt(pages),
};
myLibrary.push(book);
// Then, ask to display your book
displayBook(book)
console.log(myLibrary);
}
It should work fine :)
You can also use Proxy objects to update the DOM the moment you add a new book to the myLibrary array. For this, we will convert the myLibrary array into a new proxy object named libraryProxy and configure it.
const myLibrary = [{
title: "The Once and Future King",
author: "White",
pages: 654,
},
{
title: "The Hobbit",
author: "Tolkien",
pages: 304,
},
];
const libraryProxy = new Proxy(myLibrary, {
get(target, prop) {
return target[prop];
},
// When you add a new element to the array,
// the set method will run and here we will update the DOM
// while adding the new element as newVal to the array.
set(target, prop, newVal) {
if (Number(prop)) {
const book = newVal;
// add new book to array
target[prop] = book;
// update the dom
addBookToUI(book);
};
return true;
}
})
const bookContent = document.getElementById("content");
const form = document.getElementById("form");
form.addEventListener("submit", submitHandler);
libraryProxy.forEach((book) => {
addBookToUI(book);
})
function submitHandler(event) {
event.preventDefault();
const [title, author, pages] = document.querySelectorAll('form > input');
// New book will be added to the array and the DOM will be updated
libraryProxy.push({
title: title.value,
author: author.value,
pages: parseInt(pages.value, 10)
});
}
function addBookToUI(book) {
const bookEl = document.createElement('div');
bookEl.className = 'book';
bookContent.appendChild(bookEl);
bookEl.innerHTML += `
<div class="title">
<p class="bookTitle">
<span>${book.title}</span>
</p>
</div>
<div class="body">
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>
`;
}
.book {
border: 1px solid #000;
margin: 5px 0;
font-size: 14px;
}
<form id="form">
<input type="text" id="title" placeholder="title" />
<input type="text" id="author" placeholder="author" />
<input type="text" id="pages" placeholder="pages" />
<button type="submit">save</button>
</form>
<div id="content"></div>
(Grid js) I want the search button to be on the right side and the add button on the left, what do I do?
new gridjs.Grid({
columns: ['Name', 'Email', 'Phone Number'],
search: true,
data: [
['John', 'john#example.com', '(353) 01 222 3333'],
['Mark', 'mark#gmail.com', '(01) 22 888 4444'],
['Eoin', 'eo3n#yahoo.com', '(05) 10 878 5554'],
['Nisen', 'nis900#gmail.com', '313 333 1923']
]
}).render(document.getElementById("user-table"));
<script src="https://cdn.jsdelivr.net/npm/gridjs/dist/gridjs.production.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/gridjs/dist/theme/mermaid.min.css" rel="stylesheet" />
<div id="user-table"></div>
You can customize CSS class of the search box:
.gridjs-search {
float: right;
}
Demo: https://codesandbox.io/s/gridjs-custom-search-box-j0q9l?file=/index.html
I have the same problem as you, I did this ↓
function insertButtonToTableHeader() {
// create a button-wrapper
const button_wrapper = document.createElement('div')
button_wrapper.className = 'float-left'
// Insert buttons to button-wrapper
function insertButtonToButtonWrapper(buttonName) {
let button = document.createElement('a')
button.innerText = buttonName
button.className = 'btn btn-primary'
button_wrapper.appendChild(button)
}
insertButtonToButtonWrapper('Insert')
insertButtonToButtonWrapper('Import')
// add button-wrapper to table header
const grid_js_head = document.querySelector('.gridjs-head')
const gridjs_search = document.querySelector('.gridjs-search')
grid_js_head.insertBefore(button_wrapper, gridjs_search)
}
insertButtonToTableHeader()
for reference only, every time you forceRender() the gridjs, the button will gone, so you need to call insertButtonToTableHeader() when forceRender() executed.
I am trying to have multiple Quill text editor instances on a single page, I achieved that but now I am straggling on how to get the innerHTML of each. To create a single instance and get its innerHTML and assign it to a hidden input, I use the following:
// CREATE A QUILL INSTANCE
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{'header': [1, 2, 3, 4, 5, 6, false]}],
[{'size': ['small', false, 'large', 'huge']}],
[{'font': [] }],
['bold', 'italic', 'underline', 'strike'],
['link', 'blockquote', 'code-block', 'image', 'video'],
]
},
placeholder: 'Compose an epic...',
theme: 'snow'
});
// GET THE innerHTML OF THE QUILL INSTANCE ANS ASSIGN IT TO A HIDDEN FIELD.
var form = document.getElementById("writeArticleForm");
form.onsubmit = function() {
// Populate hidden form on submit
var articlebody = document.querySelector('input[name=articleBody]');
var html = document.querySelector(".ql-editor").innerHTML;
articlebody.value = html;
return true;
}
But when I create for instance, two instances of QUILL, how could I use the querySelector to get the innerHTML of each instance and assign it to a variable?
You can use querySelectorAll to get all elements that match a class name. To iterate over the resulting NoteList you'll have to convert it to an array, my method of choice is using the spread operator.
document.querySelector("#read_button").addEventListener("click", () => {
let output = document.querySelector("#output");
let form = document.querySelector("#form");
output.innerHTML = "";
form.innerHTML = "";
// Get all inputs
let elements = document.querySelectorAll(".input");
// Spread NodeList into array and iterate
[...elements].forEach((input, index) => {
output.innerHTML += `<li>${input.innerHTML}</li>`;
form.innerHTML += `<input type="hidden" id="input${index}_value" value="${input.innerHTML}">`;
});
});
.input {
border: 1px solid black;
padding: 0.25em;
}
#read_button {
margin-top: 1em;
}
<textarea class="input">Input 1</textarea>
<textarea class="input">Input 2</textarea>
<textarea class="input">Input 3</textarea>
<textarea class="input">Input 4</textarea>
<button id="read_button">
Read Inputs
</button>
<p>Output:</p>
<ul id="output"></ul>
<form id="form"></form>
is it possible to pass #Html.DropDownListFor current value to action link? I want to pass the template value to the Sample controller with Create Action. Below code not work because #Model.SurveyTemplate does not return any value. Is it need JavaScript to retrieve? Please guide me.
Drop Down List:
#Html.LabelFor(model => model.Survey_Template, "Survey Template")
#Html.DropDownListFor(model => model.Survey_Template, new SelectList(
new List<Object>{
new { value = "Style1" , text = "Style1" },
new { value = "Style2" , text = "Style2" },
new { value = "Style3" , text = "Style3"}
},
"value",
"text",
0))
ActionLink:
#Html.ActionLink("_", "Create", "Sample",
new { template = #Model.Survey_Template },
new { #id = "popup-link", #class = "classname2" })
You have to do this with JavaScript, the razor syntax is recognized only on server side. This means that #Model.Survey_Template will be rendered when user request the page and will have the default value.
If you choose to do it with JavaScript remember that you need to save the base url and to append parameters to it based on what has been selected.
This steps will help you to achieve your desired result:
Attach a change event on your dropdown.
Get the selected value and construct the new url
Replace the url (href) of the action (<a .. />)
Note: I didn't write the code because I want you to surpass yourself.
I think what you try to achive it's a form with GET.
#using(Html.BeginForm("Create", "Sample", FormMethod.GET)){
#Html.LabelFor(model => model.Survey_Template, "Survey Template")
#Html.DropDownListFor(model => model.Survey_Template, new SelectList(
new List<Object>{
new { value = "Style1" , text = "Style1" },
new { value = "Style2" , text = "Style2" },
new { value = "Style3" , text = "Style3"}
},
"value",
"text",
0))
<input type="submit" value="_" class="classname2" id="popup-link" />
}
I want to display a property name based on user input and display this inside of SyntaxHighlighter. Another post says this is supposed to be easy.
JS
$('#inputText').keyup(function () {
var outputValue = $('#codeTemplate').html();//Take the output of codeTemplate
$('#codeContent').html(outputValue);//Stick the contents of code template into codeContent
var finalOutputValue = $('#codeContent').html();//Take the content of codeContent and insert it into the sample label
$('.popover #sample').html(finalOutputValue);
SyntaxHighlighter.highlight();
});
SyntaxHighlighter.all();
Markup
<div style="display: none;">
<label class="propertyName"></label>
<label id="codeTemplate">
<label class="propertyName"></label>
//Not using Dynamic object and default Section (appSettings):
var actual = new Configuration().Get("Chained.Property.key");
//more code
</label>
<pre id="codeContent" class="brush: csharp;">
</pre>
</div>
<div id="popover-content" style="display: none">
<label id="sample">
</label>
</div>
This outputs plain text. As if SyntaxHighlighter never ran. I suspect that the issue has to do with the fact that <pre> doesn't exist after the page is rendered. However, updating
SyntaxHighlighter.config.tagName = "label";
along with pre to label did not work either.
There were many problems that had to be overcome to get this to function. I feel this is best explained with code:
JS
<script>
$(function () {
$('#Key').popover({
html: true,
trigger: 'focus',
position: 'top',
content: function () {
loadCodeData(true);
console.log('content updated');
var popover = $('#popover-content');
return popover.html();//inserts the data into .popover-content (a new div with matching class name for the id)
}
});
$('#Key').keyup(function () {
loadCodeData();
});
function loadCodeData(loadOriginal) {
var userData = $('#Key').val();
var codeTemplate = $('#codeTemplate').html();
var tokenizedValue = codeTemplate.toString().replace('$$propertyNameToken', userData);
$('#codeContent').html(tokenizedValue);
$('#codeContent').attr('class', 'brush: csharp');//!IMPORTANT: re-append the class so SyntaxHighlighter will process the div again
SyntaxHighlighter.highlight();
var syntaxHighlightedResult = $('#codeContent').html();//Take the content of codeContent and insert it into the div
var popover;
if(loadOriginal)
popover = $('#popover-content');//popover.content performs the update of the generated class for us so well we need to do is update the popover itself
else {
popover = $('.popover-content');//otherwise we have to update the dynamically generated popup ourselves.
}
popover.html(syntaxHighlightedResult);
}
SyntaxHighlighter.config.tagName = 'div';//override the default pre because pre gets converted to another tag on the client.
SyntaxHighlighter.all();
});
</script>
Markup
<div style="display: none;">
<label id="codeTemplate">
//Not using Dynamic object and default Section (appSettings):
var actual = new Configuration().Get("$$propertyNameToken");
//Using a type argument:
int actual = new Configuration().Get<int>("asdf");
//And then specifying a Section:
var actual = new Configuration("SectionName").Get("test");
//Using the Dynamic Object and default Section:
var actual = new Configuration().NumberOfRetries();
//Using a type argument:
int actual = new Configuration().NumberOfRetries<int>();
//And then specifying a Section:
var actual = new Configuration("SectionName").NumberOfRetries();
</label>
<div id="codeContent" class="brush: csharp;">
</div>
</div>
<div id="popover-content" style="display: none">
</div>