Use CKeditor instance in Vue.js - javascript

I am trying to implement CKeditor in my Laravel-backoffice which build its views with Vue.js
In this form I want to replace the "textarea" with name="ckeditor1" with a texteditor
<form method="POST" v-on="submit: onSubmitForm">
<div class="col-md-4">
<h1>Pagina: #{{ page.name }}</h1>
<h2>Pagina algemeen</h2>
<div class="form-group">
<label for="name">
Name
<span class="error" v-if="! page.name">*</span>
</label>
<input type="text" name="name" id="name" class="form-control" v-model="page.name">
</div>
<ul class="nav nav-tabs">
<li class="" v-repeat="page.translations" v-class="active: language == defaultLanguage"><a
data-toggle="tab" href="##{{ language }}">#{{ language }}</a></li>
</ul>
<div class="tab-content">
<div v-repeat="page.translations" id="#{{ language }}" class="tab-pane fade in "
v-class="active: language == defaultLanguage">
<h2>Pagina inhoud</h2>
<div class="form-group">
<label for="name">
Titel
</label>
<input type="text" name="title_#{{ language }}" id="title_#{{ language }}"
class="form-control" v-model="title">
</div>
<div class="form-group">
<label for="content">
Inhoud
</label>
<textarea name="ckeditor1" id="content_#{{ language }}"
class="form-control editor" v-model="content"></textarea>
</div>
<h2>Seo</h2>
<div class="form-group">
<label for="meta_keywords">
Meta keywords
</label>
<input type="text" name="meta_keywords_#{{ language }}"
id="meta_keywords_#{{ language }}" class="form-control"
v-model="meta_keywords">
</div>
<div class="form-group">
<label for="meta_decription">
Meta description
</label>
<textarea name="meta_description_#{{ language }}"
id="meta_description_#{{ language }}" class="form-control"
v-model="meta_description"></textarea>
</div>
<input type="hidden" name="page_id_#{{ language }}" id="page_id_#{{ language }}"
class="form-control" v-model="page_id" value="#{{ pageId }}">
</div>
</div>
<div class="form-group" v-if="! submitted">
<button type="submit" class="btn btn-default">
Opslaan
</button>
</div>
</div>
</form>
The #{{ }} fields are loaded and filled with json call and vue.js but there is no problem cause all fields are filled perfectly as needed. The problem is just the initializing of my editor.
This is where I get my data:
Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');
var pages = new Vue({
el: '#page',
data: {
pageId: document.querySelector('#page-id').getAttribute('value'),
pageTitle: 'Pagina',
page: [],
submitted: false,
defaultLanguage: 'nl',
errors: false
},
ready: function() {
this.fetch();
},
methods: {
fetch: function() {
this.$http.get('/api/pages/' + this.pageId, function(response) {
this.page = response;
});
},
onSubmitForm: function(e) {
e.preventDefault();
this.submitted = true;
this.errors = false;
if(this.pageId == 0) {
this.$http.post('/api/pages/', this.page, function (response) {
if (response.errors.length) {
this.errors = response.errors;
this.submitted = false;
return;
}//endif
this.submitted = false;
window.location.href = '/admin/pages';
});
}
else
{
this.$http.put('/api/pages/' + this.pageId, this.page, function (response) {
if (response.errors.length) {
this.errors = response.errors;
this.submitted = false;
return;
}//endif
this.submitted = false;
window.location.href = '/admin/pages';
});
}
}
}
});
UPDATE -> SOLVED
By adding Vue.nextTick I can initialize an editor. I added a class 'editor' to every textarea I want it to be an editor and then find all id's from the textareas with class="editor".
fetch: function() {
this.$http.get('/api/pages/' + this.pageId, function(response) {
this.page = response;
Vue.nextTick(function () {
$('textarea.editor').each(function(){
CKEDITOR.replace(this.id);
});
});
});
},

By adding Vue.nextTick I can initialize an editor. I added a class 'editor' to every textarea I want it to be an editor and then find all id's from the textareas with class="editor".
fetch: function() {
this.$http.get('/api/pages/' + this.pageId, function(response) {
this.page = response;
Vue.nextTick(function () {
$('textarea.editor').each(function(){
CKEDITOR.replace(this.id);
});
});
});
}

I am also using CKeditor with laravel-vue. You just need to set and get data with CKeditor for basic thing.
This is my main.html file in which i need CKeditor.
<div class="row">
<div class="col-md-2">
<label for="body" >Mail Body :</label>
</div>
<div class="col-md-10" >
<textarea class="ckeditor" id="body" rows="5" cols="70" name="body" v-model="template.body" ></textarea>
</div>
</div>
After that i initialize my CKeditor value in app.js file
var vm = this;
axios.post('/fetchEmailTemplate', {
'template_id' : template_id
}).then(function (response) {
vm.template = response.data.emailTemplate;
CKEDITOR.instances['body'].setData(vm.template.body);
}).catch(function (error) {
console.log(error);
setNotification(error, "danger");
});
If I'm not mistaken ckeditor replaces the original textarea by a custom template. So what you see within ckeditor will not be put into your messageArea textarea automatically. That's why you don't see any changes to your model. So, for making changes you need to replace updated text before submit in app.js file like below.
this.template.body = CKEDITOR.instances['body'].getData();

Related

How to use template inside a form in vue js

I have created a vue instance for the form
var formObject = new Vue({
el: '#amount_form',
data: {
logdate: '',
amount:'',
description:''
},
methods: {
processForm :function(event)
{
var data = {"logdate":this.logdate,"amount":parseFloat(this.amount),"description":this.description};
console.log(data);
var parameters =
{
"data":data,
"url":"save",
"type":"post",
"data_type":"JSON",
"callback":function(data)
{
alert(data);
}
}
sendDataToSErver(parameters);
}
}
});
i have a template for categories
var categorySelect = Vue.component('category-select',
{
data()
{
return{
options:[],
cat:""
}},
template:'<select class="form-control form-control-sm" v-model="cat">' +
' <option v-for="option in options" v-bind:value="option.id">{{option.name}}</option></select>',
created :function()
{
var templateObject = this;
var parameters =
{
"url":"getCategories",
"type":"GET",
"async":true,
"data_type":"JSON",
"callback":function(data)
{
templateObject.options = data;
}
}
sendDataToSErver(parameters);
}
});
i am using this template inside the form
<div class="row">
<div class="col-3">
<div class="form-group">
<label for="log_date" class="sr-only">Date</label>
<input v-model="logdate" type="datetime-local" id="log_date" class="form-control form-control-sm" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
</div>
<div class="col-3">
<div class="form-group">
<label for="amount" class="sr-only">Amount</label>
<input v-model="amount" type="text" class="form-control form-control-sm" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
</div>
<div class="col-3">
<div class="form-group">
<label for="category" class="sr-only">Category</label>
<category-select></category-select>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label for="description" class="sr-only">Description</label>
<textarea v-model="description" class="form-control" id="description" aria-label="With textarea"></textarea>
</div>
</div>
</div>
</form>
Now how can get the value in form.
You can emit an event from the child. The parent needs to listen for the custom event and get the data from there. You also need to listen for onChange on your select to emit the event.
The template for categories should be something like this
var categorySelect = Vue.component('category-select',
{
data()
{
return {
options:[],
cat:""
}
},
template:'<select class="form-control form-control-sm" v-model="cat" #change="handleUpdateSelectedValue($event)">' +
' <option v-for="option in options" v-bind:value="option.id">{{option.name}}</option></select>',
methods: {
handleUpdateSelectedValue(event) {
this.$emit('selectedValue', event.target.value) //emitting the event here
}
}
created :function()
{
var templateObject = this;
var parameters =
{
"url":"getCategories",
"type":"GET",
"async":true,
"data_type":"JSON",
"callback":function(data)
{
templateObject.options = data;
}
}
sendDataToSErver(parameters);
}
});
And now you need to listen for the event in the parent
<div class="col-3">
<div class="form-group">
<label for="category" class="sr-only">Category</label>
<category-select #selectedValue="handleSelectedValue"></category-select>
</div>
</div>
Now, the only thing that remains to do is to define handleSelectedValue in your parent component and do something with that value.
var formObject = new Vue({
el: '#amount_form',
data: {
logdate: '',
amount:'',
description:''
},
methods: {
handleSelectedValue(value) {
}
}
...

how to add multi captcha in same page and check both checkbox its fill

I have two forms on a single page, one of them is a login form and the other is a register form (two tabs) and I want to check the the captchas, but when I click the check captcha from register form I can't login.
The login form:
HTML:
<div id="loginUserTab" class="tab-pane fade">
<form>
<div class="form-group login-width-100">
<label for="id_number" class="m-rtl-label"><span class="requiredMark">*</span>passport number:</label>
<input type="text" class="form-control" id="pNo" name="pNo" data-validetta="required,minLength[10],maxLength[10]" lang="fa" style="text-align: left;">
</div>
<div class="form-group login-width-100">
<label for="mNumber" class="m-rtl-label"><span class="requiredMark"></span> telephone :</label>
<input type="text" class="form-control" id="tNumber" name="tNumber" data-validetta="required,minLength[11],maxLength[11]" lang="fa" style="text-align: left;">
</div>
<div class="form-group" style="float:right;padding-right: 20px;">
<div class="g-recaptcha" data-sitekey="...."></div>
</div>
<div class="form-group login-width-100">
<button type="submit" class="btn btn-primary colorGreenBTN">login</button>
</div>
</form>
</div>
JS:
var v = grecaptcha.getResponse();
if (v.length == 0) {
alert("fill the form");
return;
} else if (!$("#Terms").prop("checked")) {
alert("check the rules");
}
Simplest Way to validate as much g-captcha validate
Hope you have included api.js before </head> tag as per below
<script src="https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit"></script>
Your HTML Code looks like below
<div class="g-recaptcha-contact" data-sitekey="Your Site Key" id="RecaptchaField2"></div>
<input type="hidden" class="hiddenRecaptcha" name="ct_hiddenRecaptcha" id="ct_hiddenRecaptcha">
<div class="g-recaptcha-quote" data-sitekey="Your Site Key" id="RecaptchaField1"></div>
<input type="hidden" class="hiddenRecaptcha" name="qt_hiddenRecaptcha" id="qt_hiddenRecaptcha">
After you add this code in footer with tag
var CaptchaCallback = function() {
var widgetId1;
var widgetId2;
widgetId1 = grecaptcha.render('RecaptchaField1', {'sitekey' : 'Your Site Key', 'callback' : correctCaptcha_quote});
widgetId2 = grecaptcha.render('RecaptchaField2', {'sitekey' : 'Your Site Key', 'callback' : correctCaptcha_contact});
};
var correctCaptcha_quote = function(response) {
$("#qt_hiddenRecaptcha").val(response);
};
var correctCaptcha_contact = function(response) {
$("#ct_hiddenRecaptcha").val(response);
};
And Last easy step for developer add Jquery Validation as per below
$("#form_id").validate({
ignore: [],
rules: {
ct_hiddenRecaptcha: { required: true, },
qt_hiddenRecaptcha: { required: true, },
},
});
If you have same class for both the forms, you can use it to validate above.

this find label in a form does not work

I have two forms of the same class in a page. These forms are exactly the same with the same elements. On submitting one of them, I try to access the elements inside. Here is what the forms look like:
<form role="form" class="login-form" id="login-form">
{% csrf_token %}
<div class="form-group">
<div class="input-icon">
<i class="icon fa fa-user"></i>
<input type="text" class="form-control" name="email" placeholder="Username" id="email">
</div>
</div>
<div class="form-group">
<div class="input-icon">
<i class="icon fa fa-unlock-alt"></i>
<input type="password" class="form-control" placeholder="Password" name="password" id="password">
</div>
</div>
<div>
<!--input type="checkbox" id="remember" name="rememberme" value="forever" style="float: left;"-->
<label style="display: none; color: red;" id="incorrect_info">Veuillez vérifier vos informations</label>
</div>
<button class="btn btn-common log-btn">Se connecter</button>
</form>
Now the javascript where I try to access the elements:
$('.login-form').submit(function(e){
e.preventDefault();
// Get information
email = $(this).find('input[id="email"]').val();
pass = $(this).find('input[id="password"]').val();
$(this).find('label[id="incorrect_info"]').css('display','block');
});
This code works for the inputs, but not for the label, which is not found.
EDIT :
Sorry here is actually how the code looks like. The find is called in the ajax done.
$('.login-form').submit(function(e){
e.preventDefault();
// Get information
email = $(this).find('input[id="email"]').val();
pass = $(this).find('input[id="password"]').val();
$.ajax({
.......
}).done(function (data) {
if (data.success) {
window.location.href = data.url;
}
else {
$(this).find('label[id="incorrect_info"]').css('display','block');
}
});
});
I figured this out. The problem is that $(this) scope is different inside the ajax function. What I've done is to save it before getting into it, and reused it after:
$('.login-form').submit(function(e){
e.preventDefault();
// Get information
this_form = $(this);
email = $(this).find('input[id="email"]').val();
pass = $(this).find('input[id="password"]').val();
$.ajax({
......
success : function(data, status){
}
}).done(function (data) {
if (data.success) {
window.location.href = data.url;
}
else {
this_form.find('label[id="incorrect_info"]').css('display','block');
}
});
});

saving inputs from pagedown editor in the database

I am using pagedown editor to replace textarea in an app i'm building but when i get sample codes as input from the editor and save it in the database, querying it out gives the result without any formatting.
I was expecting the result to the same as the preview of pagedown editor.
this is the form
{{Form::open(array('url'=>'profile/askquestion'))}}
<div class="form-group">
<label for="inputEmail" class="control-label">Title</label>
<div class="">
<input type="text" class="form-control" id="inputEmail" name="title" value="{{ Input::old('title') != NULL ? Input::old('title') : '' }}" placeholder="What's your programming question? Be specific." autofocus>
<span class="badge alert-danger">{{ ($errors->has('title') ? $errors->first('title') : '') }}</span>
</div>
</div>
<div class="form-group">
<label for="inputEmail" class="control-label"></label>
<div class="wmd-panel1">
<div id="wmd-button-bar-second" class="pagedown-swag"></div>
<textarea class="wmd-input form-control" name="body" id="wmd-input-second" rows="10"></textarea>
<span class="badge alert-danger">{{ ($errors->has('body') ? $errors->first('body') : '') }}</span>
</div><br ><hr>
<div id="wmd-preview-second" class="wmd-preview"></div><hr>
</div>
<div class="form-group">
<div class="">
<button type="submit" class="btn btn-primary pull-right">Post Your Question</button>
</div>
</div>
{{Form::close()}}
code for saving in the database
public function postAskquestion(){
$registerData = Input::all();
$registerRules = array(
'title' =>'required',
'body' =>'required',
);
$registerValidator = Validator::make($registerData,$registerRules);
if($registerValidator->fails()) {
return Redirect::back()->withInput()->withErrors($registerValidator);
}
if( $registerValidator->passes()) {
$question = new Question();
$question->title = Input::get('title');
$question->description = Input::get('body');
$question->user_id = Auth::user()->id;
$question->save();
return Redirect::to('/')->with('alertMessage',"question posted successfully.");
}
}
code for querying the contain
Route::get('question/{id}/{slug}', function ($id, $slug) {
$data['question'] = Question::find($id);
return View::make('site.question')->with($data);
});
code for displaying the contain
<div id="wmd-preview" class="wmd-panel1 wmd-preview">{{$question->description}}</div>
Help please
I know this is old post but here is how I am doing it
I'm saving the html from wmd-preview and save it with ajax
jQuery
var value = $("#wmd-preview).html();
$.ajax({
type: "POST",
url: "path/to-your-php-file",
dataType: "html",
data: {value: value} //The first value is the variable that you're sending to PHP
})
PHP
CONNECT TO YOUR DATABASE
$value = $_POST['value];
$query = mysqli_query($db,"INSERT INTO posts VALUES('$value'));

Can't get error handing in vue.js 1.0 and Laravel 5.1 to work

I'm building an app which uses vue.js and Laravel 5 to persist data into a database. So far, it can successfully save data.
My problem
I'm having trouble with displaying errors when the user validation fails using the 'out of the box' authorisation that Laravel has. I keep getting the error:
[Vue warn]: Error when evaluating expression "form.errors.length > 0"
(referring to errors.js in my code below)
Piecing it together
So how this should work...a user enters their details into the registration page and Vue (using vue-resource) makes an AJAX request to the 'out of the box' Laravel AuthController#postRegister method. On error, Laravel nicely spits out the JSON error messages we all expect. Now in theory, the sendRegistration method within my subscription.js file should detect the errors that Laravel spits out (I've tested this with console.log's and it works) and pass them into the errors.js component to display the errors within the <spark-errors> tags. In order to do this, it uses a setErrorsOnForm: function within my <head> tag. However it's not working as expected and I cannot workout why.
My code
My code consists of a registration page:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Laravel Spark Globals -->
<script>
window.Spark = {
// Laravel CSRF Token
csrfToken: '{{ csrf_token() }}',
// Flatten errors and set them on the given form
setErrorsOnForm: function (form, errors) {
if (typeof errors === 'object') {
form.errors = _.flatten(_.toArray(errors));
} else {
form.errors.push('Something went wrong. Please try again.');
}
}
}
</script>
</head>
<body>
<div id="spark-app">
<spark-subscription-register-screen inline-template>
<div class="panel panel-default">
<div class="panel-heading">Your Information</div>
<div class="panel-body">
<spark-errors form="#'{'{ registerForm '}'}"></spark-errors>
<form class="form-horizontal" role="form" id="subscription-basics-form">
<div class="form-group">
<label class="col-md-4 control-label">Your Name</label>
<div class="col-md-6">
<input type="text" class="form-control spark-first-field" name="name" v-model="registerForm.name">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" v-model="registerForm.email">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password" v-model="registerForm.password">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password_confirmation" v-model="registerForm.password_confirmation">
</div>
</div>
<div v-if="freePlanIsSelected">
<div class="form-group">
<div class="col-sm-6 col-sm-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" v-model="registerForm.terms"> I Accept The Terms Of Service
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-6 col-sm-offset-4">
<button type="submit" class="btn btn-primary" v-on:click="register" :disabled="registerForm.registering">
<span v-if="registerForm.registering">
<i class="fa fa-btn fa-spinner fa-spin"></i> Registering
</span>
<span v-if=" ! registerForm.registering">
<i class="fa fa-btn fa-check-circle"></i> Register
</span>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</spark-subscription-register-screen inline-template>
</div>
</body>
</html>
From a vue.js perspective there is a subscription.js file:
Vue.component('spark-subscription-register-screen', {
/*
* Initial state of the component's data.
*/
data: function () {
return {
registerForm: {
nhs_org: '', team_name: '', name: '', email: '', password: '', password_confirmation: '',
plan: '', terms: false, coupon: null, invitation: null,
stripe_token: null, errors: [], registering: false
},
};
},
methods: {
/*
* Initialize the registration process.
*/
register: function(e) {
var self = this;
e.preventDefault();
this.registerForm.errors = [];
this.registerForm.registering = true;
return this.sendRegistration();
},
/*
* After obtaining the Stripe token, send the registration to Spark.
*/
sendRegistration: function() {
this.$http.post('/register', this.registerForm)
.success(function(response) {
window.location = '/';
})
.error(function(errors) {
this.registerForm.registering = false;
Spark.setErrorsOnForm(this.registerForm, errors);
});
},
}
});
and there is an errors.js Vue component:
/*
* Common Error Display Component.
*/
Vue.component('spark-errors', {
props: ['form'],
template: "<div><div class='alert alert-danger' v-if='form.errors.length > 0'>\
<strong>Whoops!</strong> There were some problems with your input.<br><br>\
<ul>\
<li v-for='error in form.errors'>\
{{ error }}\
</li>\
</ul>\
</div></div>"
});
Now the Vue files which piece all of this together (in the correct order):
app.js:
require('./core/dependencies');
if ($('#spark-app').length > 0) {
new Vue(require('./core/spark.js'));
}
core/dependencies.js:
/*
* Load Vue & Vue-Resource.
*
*/
if (window.Vue === undefined) window.Vue = require('vue');
require('vue-resource');
Vue.http.headers.common['X-CSRF-TOKEN'] = Spark.csrfToken;
/*
* Load Underscore.js, used for map / reduce on arrays.
*/
if (window._ === undefined) window._ = require('underscore');
/*
* Load jQuery and Bootstrap jQuery, used for front-end interaction.
*/
if (window.$ === undefined || window.jQuery === undefined) window.$ = window.jQuery = require('jquery');
require('bootstrap-sass/assets/javascripts/bootstrap');
core/spark.js:
/*
* Load the Spark components.
*/
require('./components');
/**
* Export the Spark application.
*/
module.exports = {
el: '#spark-app',
/*
* Bootstrap the application. Load the initial data.
*/
ready: function () {
$(function() {
$('.spark-first-field').filter(':visible:first').focus();
});
}
}
and core/components.js:
require('./../auth/registration/subscription');
require('./../common/errors');
I had the same issue, and instead of using the out of the box errors from spark, I defined my own component:
<template>
<div v-if="errors">
<div class="alert alert-danger" v-if="formattedErrors.length > 0">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
<li v-for="error in formattedErrors">
{{ error }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ['errors'],
computed: {
formattedErrors() {
return this.format(this.errors);
}
},
methods: {
format(errors) {
if (typeof errors === 'undefined') {
return [];
}
if (typeof errors === 'object') {
return _.flatten(_.toArray(errors));
}
}
}
}
</script>
Then you bind in your html:
<form-errors :errors="registerForm.errors"></form-errors>
It makes sense because your component just need the to now about errors, and nothing else about the registerForm.
Hope this helps.

Categories

Resources