Vuejs Input Binding Based on Array of Computed Properties - javascript

I have a scenario where I want the v-model binding of an Input field to be decided by the value returned by a computed property.
Please see the example below:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue#2.1.10/dist/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="app">
{{value}}
<input type="text" v-model="myName.first">
<input type="text" v-model="myName.second">
</div>
<script>
new Vue({
el:'#app',
data:{
value:{
first: '',
second: ''
}
},
computed: {
myName: {
get(){
return {first:'this.value.first',second:'this.value.second'}; //this will actually come from an API
},
set(newValue){
this.value.first = newValue.second;
this.value.second = newValue.second;
}
}
}
});
</script>
</body>
</html>
As you can see in the above code, I want the first field to be bound to value.first and second value to be bound to value.second. For both fields, I want the model binding to be decided by the value returned from computed property. Right now it's a simple example and there are only two returned value, i.e., value.first and value.second. But this will be decided on logic.
I feel I am not making use of get and set correctly. Really appreciate any help.
Note: I had a previous question on similar lines but it had only one value returned in computed property instead of an array/object. The answer provided worked great However, this time the challenge is that we have two values that need to be set. You can see that thread here: Vuejs Input Binding Based on Computed Property

You can v-model directly to a computed property without using data or set/get.
CodePen
<input type="text" v-model="myName.first">
data:{},
computed: {
myName: function() {
return this.$store.state.myName; //or whatever your api is
}
}
Also, make sure the value of your computed property is present before your input loads.

Related

is not defined on the instance but referenced during render but works as i want

now im learning vuejs, and have some problem,
i hope someone can help me.
i've index.html and app.js, when i run in browser in the console it printed :
vue.js:634 [Vue warn]: Property or method "count" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
but the question is, why the function still work when i click the button?
here is my complete code:
Vue.component('click-counter', {
template: '<button #click="count++">{{ count }}</button>',
data() {
return {
count: 0
}
}
})
Vue.component('click-counter-using-defined-template', {
template: '#click-counter-template',
data() {
return {
count: 0
}
}
})
new Vue({
el: '#app'
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learning</title>
</head>
<body>
<div id="app">
<h1>learning component</h1>
<!-- basic component -->
<click-counter></click-counter>
<!-- component template -->
<!-- Remember! Component template must contain exactly one root element. -->
<click-counter-using-defined-template></click-counter-using-defined-template>
<script type="text/x-template" id="click-counter-template">
<div style="border: 1px dashed orange;">
<p>we re counter</p>
<button #click="count++">{{ count }}</button>
</div>
</script>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="./app.js"></script>
</body>
</html>
In your code, "text/x-template" is actually inside the div the vue instance is attached to. Vue documentation states that template definition in this manner needs to be outside the attached DOM element, By moving the template code outside the attached div, the warning goes away.
https://v2.vuejs.org/v2/guide/components-edge-cases.html#X-Templates
Your x-template needs to be defined outside the DOM element to which Vue is attached.
In your code, Vue is encountering 'count' inside the attached div, but 'count' is not actually defined inside the root instance. The warning most likely stems from this.

Change property of vue img uploader

I'm trying to upload my images with this vue.js. i'm using this plugin for the task. But I need to change the language. In doc it's said we can change it by using props. And I did,
:drag-text='drag_text'
Here is my complete code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-upload-multiple-image</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div>
<div id="car_ad_others"></div>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.22/dist/vue.js"></script>
<script type="text/javascript">
var parent = $('#car_ad_others').parent();
parent.html('<div id="car-image-upload"><upload-component></upload-component></div>');
$('#car_ad_others').parent().attr('id', 'car_ad_parent');
Vue.component('upload-component', {
props: ['dragText'],
data: function () {
return {
images: '',
uploadImageSuccess: '',
beforeRemove: '',
editImage: '',
dataChange: '',
drag_text: 'ddd'
};
},
template: "<div id='my-strictly-unique-vue-upload-multiple-image' style='display: flex; justify-content: center;'><vue-upload-multiple-image :drag-text='drag_text' #upload-success='uploadImageSuccess' #before-remove='beforeRemove' #edit-image='editImage' #data-change='dataChange' :data-images='images'></vue-upload-multiple-image></div>"
});
new Vue({el: '#car-image-upload'});
</script>
<script src="https://unpkg.com/vue-upload-multiple-image#1.0.2/dist/vue-upload-multiple-image.js"></script>
</body>
</html>
Unfortunately it didn't got translated and I'm getting this error too,
[Vue warn]: Unknown custom element: - did
you register the component correctly? For recursive components, make
sure to provide the "name" option.
Properties are in this link. And I have simplified my code to show the issue easier. So I cant change the structure.
It seems, there's a bug in the library itself. The codepen in the document doesn't seem to respond to props change. About your [Vue warn]: Unknown custom element: warning, somehow this worked for me:
components: {
'vue-upload-multiple-image': () => import('https://unpkg.com/vue-upload-multiple-image#1.0.2/dist/vue-upload-multiple-image.js')
},
and comment <script src="https://unpkg.com/vue-upload-multiple-image#1.0.2/dist/vue-upload-multiple-image.js"></script>
I am still trying to figure out how but it should be something related to local registration components vs global registration of the components. I will improve this answer as I come along with better and concrete explanation
try this
:drag-text="drag_text"
:drag-text = "'your text as string'"

How can I make a JavaScript function wait for input or value?

As you can see below, I have a function,createCharacter(), that calls another function, getUserInput(). This function is intended to grab the value of a text input element and return that value to be stored in the "name" variable within the createCharacter. However, if you run this code. It completely runs through both functions, never giving the opportunity for the user to input a value. Perhaps a more specific question is, how can I make this function wait for the variable to be defined before returning it to createCharacter? I've tried to wrap the code in a while loop that will run for as long as value is undefined. Didn't work, created an infinite loop and crashed. ANY solution to this problem will be greatly appreciated. I feel like the solution is so simple, but I just can't figure it out for the life of me. Thanks.
var messageDisplay = document.querySelector(".message-display");
var menuInput = document.querySelector(".menu-input");
var playerInput = document.querySelector(".player-text")
function createCharacter() {
messageDisplay.textContent = "Welcome! What is your name?";
var name = getUserInput();
messageDisplay.textContent = "Hello " + name + "!";
}
function getUserInput() {
var textValue = playerInput.value;
return textValue;
}
createCharacter();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="message-display"></div>
<div class="menu-input">
<form class="menu-input-content">
<input class="player-text" type="text">
<input class="submit-button" type="submit">
</form>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
I think you have a misunderstanding of how the DOM and the user interact. The DOM is event based. You can start by add an change event listener to your input element (or on the submit button):
menuInput.onchange = createCharacter;
And then remove the call to createCharacter, the last line in the code you posted.
This will then call the createCharacter() method when you change the text in the input at all, which is probably not what you want. You could also try:
var menuSubmit = document.querySelector(".submit-button");
menuSubmit.onclick = createCharacter;
And that is probably more on the right track.
However, given your misunderstanding in the first place, perhaps you need to reconsider how you approach your design?
The reason it runs through the code immediately is because of the last line. The browser loads the JS and executes everything in the global scope. Your query selectors are run and stored in those variables, the functions defined, and then on the last line you call one of the defined functions.
To fix this you need to redesign your app to be event based. Keep defining needed variables and functions in the global scope, as you are doing here, but then change your execution to be in response to events.
I think you are looking for something like this. You should be using the events to get what you wanted. You are executing createCharacter() before even the user clicked the Submit button. Hence you see "Hello !" as there is no user input initially.
function submitClicked(event) {
var messageDisplay = document.querySelector(".message-display");
var playerInput = document.querySelector(".player-text");
messageDisplay.innerHTML = "Hello " + playerInput.value;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="message-display"></div>
<div class="menu-input">
<input class="player-text" type="text">
<input class="submit-button" onclick="submitClicked()" type="submit">
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>

setting Angular select ng-init to first value in array

I have a simple select element that I am trying to enforce a value being present to submit the form and I have tried both setting the required attribute as well as using ng-init to ensure there is a value selected and both fail.
I am using ng-options to create a list of values from an array of Objects that have a ref property. Then I would like to use ng-init to set the shown value to the first Object.ref in the array.
<select name="refmarker" class="input-block-level form-width-adjust" ng-model="model.refmarker" ng-options="rm.ref for rm in refmarkers" ng-disabled="editable" ng-init="model.refmarker='refmarkers[0].ref'" required></select>
I have tried the following without any luck
ng-init="model.refmarker='refmarkers[0]'"
ng-init="model.refmarker='refmarkers[0].ref'"
ng-init="model.refmarker='rm.ref'"
Also the required attribute doesn't work ? Is the angular select element buggy or am I doing something wrong?
required will only work in side a form element.
What you want is ng-init="model.refmarker=refmarkers[0]"
<!doctype html>
<html lang="en" data-ng-app="app">
<head>
<meta charset="utf-8">
<title>Test</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script>
<script type="text/javascript">
angular.module('app',[])
.controller('Main',function($scope)
{
$scope.model = {};
$scope.refmarkers = [{ref:'abc'},{ref:'def'},{ref:'ghi'}];
});
</script>
</head>
<body ng-controller="Main">
{{'Angular'}}
<select ng-model="model.refmarker" ng-options="rm.ref for rm in refmarkers" ng-init="model.refmarker=refmarkers[0]"></select>
{{model.refmarker}}
</body>
</html>

JavaScript resolve string to equivalent object

I am writing a JavaScript utility which allows a user to detect if a particular object / function is available at runtime. Here is the source code, this works but it needs editing every time you want to test for another object:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Template</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#TestObject').click(function() {
alert(typeof(HTMLCollection));
});
});
</script>
</head>
<body>
<input id="ObjectType" type="text" />
<input id="TestObject" type="button" value="Test" />
</body>
</html>
When the button is clicked, it displays an alert indicating "object" or "function" if the item exists, and "undefined" if it does not.
What I want is to have a textbox <input id="ObjectType" type="text" /> where I can type in the object to test, and then click the button to test it, which will eliminate the need to keep editing the document. Is this possible? Is there anything similar to reflection that I can use?
This is possible due to JavaScript object properties actually being associative key-value pairs, meaning that obj.property is equivalent to obj['property'].
Applying this to your problem, the following code would work:
alert(typeof(window[$('#ObjectType').val()]));
This works because all "global" variables, are actually properties of the window object.
You can get the object from a string-ed class name by doing window[className]. We'll use that by getting the string value of a class name from the input text box, getting the object from the class name, and calling typeof against it:
Keeping your code the same just replace alert(typeof(HTMLCollection)); with alert(typeof(window[$("#ObjectType").val()]));

Categories