Using Vue with Redactor [duplicate] - vue.js

This question already has answers here:
jQuery plugin in Vue component: Cannot pass value to prop
(4 answers)
Closed 5 years ago.
I am using a v-model on Redactor. When I do this it returns "Event" not the actual data I'm looking for. Any ideas on how to return the correct data?
HTML
<div id="question-create-form">
<textarea class="form-control question-create-editor" id="question_description" rows="3"></textarea>
</div>
JS
$('#question-create-form .question-create-editor').redactor({
imageUpload:'/urlGoesHereBro/',
plugins: ['video', 'imagemanager', 'counter', 'limiter'],
buttonsHide:['html', 'formatting', 'deleted', 'indent', 'outdent', 'alignment', 'horizontalrule']
});
$('#question-create-form .redactor-editor').attr('v-model', 'questionDescription');

Redactor appears to be a jQuery widget, which means it works by manipulating the DOM. Vue expects to control the DOM, which means the two are going to step on each others' toes unless you confine your (Redactor's) DOM manipulations to the lifecycle hooks of a wrapper component.
To make your Redactor component work with v-model, it will need to:
accept a value prop
emit an input event with the new value

Related

Is is possible to call watch() on an input ref in Vue 3 to watch the input's value attribute?

I know that we can use the v-model directive on an <input> element and use watch() to trigger a function when the state of the <input>'s value attribute changes.
I'm trying, however, to watch an <input> ref. When I do, the watcher's function is executed when the element is mounted to the DOM, but does not trigger when the <input>'s value attribute changes.
Am I doing something wrong?
<script setup>
import { ref, watch, watchEffect } from 'vue'
const refA = ref(null)
watch(refA, () => {
console.log('refA changed')
console.log(refA)
console.log(refA.value)
console.log(refA.value.value)
}, { deep: true })
</script>
<template>
<input ref="refA" type="text" value="test" /> <br />
</template>
From what I know, template refs can be watched, but they only fire when the .value changes - that's the value of the ref, i.e. the HTML element, not the value of a HTML input element. That fits with what you describe, the watcher firing once at mount and never again. Also, it is not possible to deep-watch a HTML element.
It is fascinating to me how different template refs and data felt in Vue 2, when apparently the mechanism on script-side was always the same, which is now made obvious in Vue 3 composition API. But they still do different things, where one gives access to a HTML element or a Vue component instance, and the other stores a value. I guess the big difference comes from using a ref in the ref attribute, not from the way it is declared.
Anyway, if you want to bind to the value of an input, use v-model (or v-bind:modelValue and #update:modelValue), but if you need access to the node for whatever reason, use ref=. If you want to do both, you need to use both, it is not possible to use just the template ref.
I am not sure what you are trying to achieve. if you don't need to use v-model then you should use v-bind and emit the input event, like the below.
<template>
<input :value="refA" type="text" #input="refA = $event.target.value" /> <br />
</template>
This will trigger watch on every update to your input.
A template ref which you have used as part of your example cannot be used to watch the internal value of the component.See below comments thread regarding the same.

Watching a dynamically rendered field in Laravel Nova Vue component

In Laravel Nova, action modals are rendered in Vue by retrieving a list of fields to display through a dynamic component. I have replaced the action modal with own custom component, but am struggling to achieve the effect I want without also extending the entire set of components for rendering form fields.
I have my CustomResourceIndex.vue, containing a conditionally loaded (via v-if) ActionModal.vue, in which the form fields are rendered like so:
<div class="action" v-for="field in action.fields" :key="field.attribute">
<component
:is="'form-' + field.component"
:resource-name="resourceName"
:field="field"
/>
</div>
where the actual form field component is chosen based on the field.component value.
Those form fields (which I ideally do not want to have to extend and edit) are rendered like so:
<template>
<default-field :field="field" :errors="errors">
<template slot="field">
<input
class="w-full form-control form-input form-input-bordered"
:id="field.attribute"
:dusk="field.attribute"
v-model="value"
v-bind="extraAttributes"
:disabled="isReadonly"
/>
</template>
</default-field>
</template>
I would like to watch the value of specific fields and run methods when they change. Unfortunately due to a lack of ref attribute on the input elements or access to the value that the form element is bound to, I'm not sure how I can accomplish that from within ActionModal.vue.
I am hoping that because I have access to the ids still, there is some potential way for me to emulate this behavior.
Many resources I've found on my own have told me that anything with an ID is accessible via this.$refs but that does not seem to be true. I can only see elements that have an explicitly declared ref attribute in this.$refs, so I am not sure if I've misunderstood something there.
I would recommend looking into VueJS watch property.
You can listen to function calls, value changes etc.
watch: {
'field.component': function(newVal, oldVal) {
console.log('value changed from ' + oldVal + ' to ' + newVal);
},
},
Are those components triggering events? Try looking into the events tab of the Vue DevTools to see if some events are triggered from the default-field component when you update the value.
My guess is that you could write something like:
<div class="action" v-for="field in action.fields" :key="field.attribute">
<component
:is="'form-' + field.component"
:resource-name="resourceName"
:field="field"
#input="doSomething($event)"
/>
</div>
The $event value being the new value of the field.
Hit me on the comments if you have more info on the behavior of the default form fields (Are their complete code accessible somewhere?).

Convert from jQuery to Vue?

I would like to transform the following code which is in javascript:
$('a').click(function() {
$(this).find('i').toggleClass('fa-heartbeat');
});
in vue.js.
function name: like
javascript test: https://jsfiddle.net/jsk590ep/
In Vue, you typically don't select and manipulate DOM elements directly, you rather bind data to parts of the markup within your Vue components.
That said: You don't even need a function for that.
Simply
add a data element that indicates which state the icon is in (see https://v2.vuejs.org/v2/guide/#Declarative-Rendering)
change its value in the #click handler of the surrounding a, see https://v2.vuejs.org/v2/guide/events.html#Listening-to-Events
conditionally bind the fa classes based on the state to the icon, see https://v2.vuejs.org/v2/guide/class-and-style.html
<a href="#" #click="liked = !liked">
<i :class="['fa', liked ? 'fa-heartbeat' : 'fa-plus-circle']"></i>
</a>
When looking at the vue docs, note that #click in the example is a shortcut for v-on:click and :class for v-bind:class.
Working example here: https://codesandbox.io/s/stack-overflow-q-57403395-ul62e?module=/src/App.vue

Can VueJS components be passed an expression/function to run? [duplicate]

This question already has an answer here:
Pass method from parent component to child component in vuejs
(1 answer)
Closed 5 years ago.
First of all, please go easy on me, I'm new to Vue and still trying to understand it but I'm experienced in Angular.
I'm trying to find the Vue equivelant of this code, which uses an Angular-UI component...
<uib-datepicker date-disabled="myController.isDateDisabled(day)"></uib-datepicker>
and in the controller:
vm.isDateDidabled = function(day){
return (day === 7); // Example test for Sundays
};
The component uses a passed expression from your controller using a '&' binding and runs it when it needs to. I haven't seen this done in Vue yet. Can this be done with props?
Absolutely.
Lets take your example - we have a datepicker:
<date-picker></date-picker>
Vue components can recieve props. If we wanted to give the date picker component a "disabled" prop it would look this this:
<date-picker v-bind:disabled="true"></date-picker>
When you use the v-bind directive, the expression inside the quotes is evaluated as javascript, with the assumed context being the component whose template this is.
So if we have a component:
Vue.component('parent', {
methods: {
isDisabled (day) {
return day === 7
}
}
})
You can simply execute that method to get the value for the prop (this will be re-evaluated every time the component renders).
<date-picker v-bind:disabled="isDisabled(5)"></date-picker>

vuejs 2 v-for :key not working, html being replaced?

I'm rendering some HTML in a v-for
But everytime I change any of the data, all my html gets replaced (input fields lose their values)
I tried giving the :key all kinds of different values
I didn't have this problem in vue v1, only in v2
http://jsbin.com/jomuzexihu/1/edit?html,js,output
I had a little play with this and it appears that Vue does not re-render the entire list when using <input /> or if you use a component but it does with v-html. Heres the fiddle for the comparison:
https://jsfiddle.net/cxataxcf/
The key actually isn't needed here because the list isn't being re-ordered, so your issue isn't to do with :key but rather with v-html. Heres what the docs say about v-html:
The contents are inserted as plain HTML - data bindings are ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.
So I guess this is where the problem lies.
It might be worth raising an issue on Vue's github page to see whether this is the expected behavior for v-html, but Vue 2.0 is much more heavily focused on components than vue 1.x and doesn't appear to recommend using v-html, so it may just be that you need to re-factor your code to use components instead.
Edit
The solution to this problem is to simply wrap the code in a component and pass the HTML as a prop:
Vue.component('unknown-html', {
props: {
html: ""
},
template: '<div><div v-html="html"></div>'
})
The markup:
<unknown-html :html="thing.html"></unknown-html>
And the View model:
var app = new Vue({
el: '#app',
data: {
numInputs: 1,
stuff: [{
'html':'<input />'
}, {
'html':'<button>Foo</button>'
}]
}
})
Here's the JSFiddle: https://jsfiddle.net/wrox5acb/
You are trying to inject raw html directly into the DOM. Probably it was possible in earlier versions of Vue.js, but it is definitely not the recommended way.
You can instead have an array of objects and bind it to html as shown in this jsFiddle: https://jsfiddle.net/43xz6xqz/
Vue.js version: 2.0.3
In the example above, vue.js is responsible for creating the input elements and also for binding these input elements to the object values using v-model.
To extract these values, you may use a computed property as shown in the sample code.
I guess, for performance optimization, when the key is not change, Vue will not rerender the dom, but will update the data import through directive.So when your input element is import through an directive (v-html), it will be rerendered everytime when stuff changes.
Due to the vue is not a string template engines, but template based on dom, so in the case of #craig_h 's example , to use the incomming html in a string template within a component:
Vue.component('unknown-html', {
props: {
html: ""
},
template: '<div><div v-html="html"></div>'
})
view:
<unknown-html :html="thing.html"></unknown-html>
So when the stuff changes, it will not to rerender the template declare in string, for vue is not a string template engine.