Vuejs set value of hidden input as route param - javascript

I am trying to set the value of a hidden input with a value of id so that when I submit my form, I have the id. I know that this value is being passed using a param as follows:
<td><router-link :to="{ name: 'editclient', params: { id: client.id }}">Edit</router-link></td>
Then in my EditClient component I have the following hidden input:
<input type="hidden" value="{{this.$route.params.id}}" v-model="id">
The issue is that this won't compile, is there another way to do this?
I can see that the value of my id is set to 1 which is what it should be in this case:
However the issue is that I can't bind this to my hidden input.
Any help is appreciated, thanks

In this case I would probably just use v-model
<input type="hidden" v-model="id">
And then set id either in data or when the route changes.
data(){
return {
id: this.$route.params.id
...
}
}

Just for reference incase someone else hits this issue, I managed to solve this by using a computed attribute in my component:
computed: {
id () {
return this.$route.params.id
}
},

Related

using the v-modeled data in two variable in vue

I v-model a data in my vue html to validate it in my form , but i also want to use it in other variable too
this is my html
<input class="input-style px-3" :class="{'border-red-error':v$.categoryTitle.$errors.length>0}" type="text"
placeholder="title" :disabled="formIsSending" v-model="DataForValidating .categoryTitle">
this is my js code , but it does not work
const DataForValidating = reactive({
categoryTitle: '',
categorySlug: '',
})
const categoryFormData = {
categoryTitle: DataForValidating.categoryTitle,
categorySlug: DataForValidating.categorySlug,
}
i made categoryFormData reactive too , but it does not work
use #input event and pass a function then store "DataForValidating.categoryTitle"
in another variable
or you can directly use arrow function in #input event to assign that v-model variable to another
i got answer , i need to use watcher
watch:{
'newCategoryData.categoryTitle': function (newVal){
this.categoryFormData.categoryTitle=newVal
},
'newCategoryData.categorySlug': function (newVal){
this.categoryFormData.categorySlug=newVal
},
}

How to pass/delete array params in HTTP Params with Angular

I have an Array of statuses objects. Every status has a name, and a boolean set at false by default.
It represent checkbox in a form with filters, when a checkbox is checked bool is set at true :
const filters.statuses = [
{
name: "pending",
value: false
},
{
name: "done",
value: false
},
];
I am using Angular HTTP Params to pass params at the URL.
filters.statuses.forEach((status) => {
if (status.value) {
this.urlParams = this.urlParams.append('statuses[]', status.name);
}
});
Url params looks like when a status is checked :
&statuses%5B%5D=pending
My problem is when I want to unchecked.
I know HTTP Params is Immutable, so, I'm trying to delete the param when checkbox is unchecked, so set to false :
...else {
this.urlParams = this.urlParams.delete('statuses');
}
But, it not works, URL doesn't change.
And if I re-check to true after that, the URL looks like :
&statuses%5B%5D=pending&statuses%5B%5D=pending
How can I delete params, if the status value is false, and keep others statuses in URL ?
Project on Angular 10.
Thanks for the help.
UPDATE : It works to delete, my param name was not good :
else {
this.urlParams = this.urlParams.delete('statuses[]', status.name);
}
But, my other problem, it's when I check 2 or more checkbox, the append function write on URL : &statuses%5B%5D=pending&statuses%5B%5D=pending&statuses%5B%5D=done
I have prepared an example to try to answer your question (If I understand this right way).
You can change the checkboxes state or the URL to play with it. Also, I added helper buttons, which will navigate you to different cases (by changing the URL).
Here is the example: https://stackblitz.com/edit/angular-router-basic-example-cffkwu?file=app/views/home/home.component.ts
There are some parts. We will talk about HomeComponent.
You have ngFor which displays statuses, I handled state using ngModel (you can choose whatever you want).
You have a subscription to the activatedRoute.queryParams observable, this is how you get params and set up checkboxes (the model of the checkboxes)
You have the ngModelChange handler, this is how you change the route according to the checkboxes state
Let's focus on 2 & 3 items.
The second one. Rendering the correct state according to the route query params. Here is the code:
ngOnInit() {
this.sub = this.activatedRoute.queryParams.subscribe((params) => {
const statusesFromParams = params?.statuses || [];
this.statuses = this.statuses.map((status) => {
if (statusesFromParams.includes(status.name)) {
return {
name: status.name,
active: true,
};
}
return {
name: status.name,
active: false,
};
});
});
}
Here I parse the statuses queryParam and I set up the statuses model. I decide which is active and which is not here.
The third one. You need to update the URL according to the checkboxes state. Here is the code:
// HTML
<ng-container *ngFor="let status of statuses">
{{ status.name}} <input type="checkbox" [(ngModel)]="status.active" (ngModelChange)="onInputChange()" /> <br />
</ng-container>
// TypeScript
onInputChange() {
this.router.navigate(['./'], {
relativeTo: this.activatedRoute,
queryParams: {
statuses: this.statuses
.filter((status) => status.active)
.map((status) => status.name),
},
});
}
Here you have the ngModelChange handler. When any checkbox is checked/unchecked this handler is invoked. In the handler, I use the navigate method of the Router to change the URL. I collect actual checkboxes state and build the query parameters for the navigation event.
So, now you have a binding of the checkboxes state to the URL and vice versa. Hope this helps.

Using v-bind and v-on instead of v-model vuejs

I was using v-model to handle inputs in a form, I had to change it to bind props values, at first input was like
<input type="text" class="form-control" placeholder="" v-model="username">
and now it looks like
<input type="text" class="form-control" placeholder="" v-bind:value="modelData.username" v-on:input="username = $event.target.value">
modelData is coming in props. and it has username.
when Using model, in data, i had defined
data: () => {
return {
username: ""
}
},
and It was working fine, but after changing it to v-bind and v-on,
My question is how I can now get the value of username in methods? as in past, I was getting it as this.username to get the value and also clear it as well but now how I can get username in
methods: {}
I have a button to save input
<button class="btn btn-secondary" type="button" #click="validateFormAndSave($event)">Save</button>
When validateFormAndSave get called I can have this.username right now I cannot get the value? But the Vue Doc says v-model and v-bind:value& v-on:input are the same?
UPDATE:
There can be and cannot be some value already there in username, as it being filled with props value, So v-on:input="username = $event.target.value" don't get the already written value but the only new one you entered? or edit it? Why is it so? is there any method for just to get what anyone typed in there or already been typed?
UPDATE:
This is getting very ambiguous. So for now.
1. I can set v-bind:value, But I cannot get it in methods without editing it.
2. I cannot set this.username = "" and it will not be removed from input as well.
3. #input only get what you newly typed not what already in there
v-model is just syntax sugar for =>
<input :value="modelValue" #input="modelValue = $event.target.value"/>
If you want something else, it's very easy to do. Just change the update side to onInput:
<input
class="form-control"
:value="username"
#input="username = $event.target.value"
>
Then
data: () => {
return {
username: ""
}
},
mounted()
{
this.username = this.modelData.username;
},
methods:{
consoleUsername() {
console.log(this.username);
}
}
The best possible solution can be when you are getting your data from props and also loading it a form for v-models.
Using watch feature of Vue component.
First I added props as
export default {
props: ["vendorModelData"],
and then I pass it through the watch to v-model
watch: {
vendorModelData() {
this.updatePropsValue(this.vendorModelData)
console.log("data updated")
}
},
in this way, it always loads differently when Props get changed. This way I got be using v-model as well as load data from props to it.
I found it useful for me.

How to loop through a list of components in VueJS

I may have gone about this completely the wrong way from the beginning so all advise is welcomed.
I am trying to create a basic page with inputs on the right and hints for the inputs on the left and when you focus on the inputs the appropriate hint is highlighted on the left.
There is a JSFiddle here: https://jsfiddle.net/eywraw8t/210693/
This will not work as I do not know how to find the appropriate hint to highlight (and set isHighlighted to false on all the other hints).
I managed to get a working example by adding a highlighted prop on the field object and not using a hint component. However in reality the fields data will come from the database so it won't have a highlighted parameter so a hint component seemed more sensible.
To put my question in simple terms: How can I find the relevant hint component when focused on an input?
JS Fiddle showing functionality without a component: https://jsfiddle.net/as2vxy79/
Broken JS Fiddle trying to use a component: https://jsfiddle.net/eywraw8t/210693/
Here is the JS outside JS Fiddle:
Vue.component('hint', {
template: `
<div class="hint" :class="{'highlight-hint': isHighlighted }">
<slot></slot>
</div>
`,
data() {
return {
isHighlighted: false
}
}
});
new Vue({
el: "#app",
data: {
fields: [
{
'id': 'name',
'hint': 'Put the name here'
},
{
'id': 'description',
'hint': 'Put the description here'
},
{
'id': 'more',
'hint': 'Put more here'
}
]
},
methods: {
onFocus(focusedField) {
// Somehow loop through the hints
// I am aware there is no "hints" property this is an example
this.hints.forEach(function(field) {
field.isHighlighted = (focusedField == field.id)
})
}
}
})
Short answer: you don't need a direct reference to the components displaying the hint because you can solve this problem using reactivity.
Only thing you need to do is add a data field which stores the field id you want to highlight and then conditionally add a class to the hint you want to highlight based on the selected id (or render the components conditionally).
new Vue({
el: "#app",
data: {
highlightedFieldId: '',
fields: [
{
'id': 'name',
'hint': 'Put the name here' },
{
'id': 'description',
'hint': 'Put the description here' },
{
'id': 'more',
'hint': 'Put more here' }
]
},
methods: {
onFocus(focusedFieldId) {
this.highlightedFieldId = focusedFieldId;
}
}
})
Here's an update to your Fiddle.
NOTES:
If you really need direct references you can use the ref directive (this also works in a list of components generated by v-for).
You should probably think about using tooltips for the hints. E.g. using Element UI's Tooltip.
UPDATE:
So, here's a solution using the ref directive to obtain a reference to the highlighted hint component. You can see that I used the field id in :ref but you still get an array from this.$refs[focusedFieldId] since there is a surrounding v-for. Other than that, it's pretty simple.
I also updated the hint component to accept the is-highlighted prop so it can change its class on its own (you previously used a data property for this which does not result in a component update).

Polymer 3: How to implement two way data binding for radio input

I'm trying to understand/implement two way attribute binding in a Polymer 3 web component. I've got the following code:
import {html, PolymerElement} from '#polymer/polymer/polymer-element.js';
class CustomInputComponent extends PolymerElement {
static get template() {
return html`
<div>
<template is="dom-repeat" items="{{ratings}}">
<input type="radio"
name="group"
id="item_{{item.id}}"
value="{{item.checked}}"
checked$="{{item.checked}}">
</template>
</div>`;
}
static get properties() {
return {
ratings: {
type: Array,
value: [
{ id: 1, checked: true },
{ id: 2, checked: false }
]
}
};
}
}
window.customElements.define('custom-input-component', CustomInputComponent);
As you can see, I have defined a Array property containing a default list of values. This property is a model from which I want to render a radio group. The initial state looks good. But when I click on the unchecked input, the DOM elements don't update correctly.
I'd bet I'm missing something really simple...
The main things are:
You are binding to the checked attribute ($=), however I don't think radio inputs dynamically update their checked attribute. AFAICT, the checked property is what changes when the input gets selected.
Also, native <input type="radio"> inputs will only fire their change and input events when they are selected, not when they are de-selected. Polymer relies on events to trigger property effects like data bindings; this means that an upwards data binding (from the input to your custom element) will only get processed when the checked property on an input changes from false to true. Effectively, once ratings[n].checked becomes true, it will never be made false because Polymer has no way to know that this has occurred.
Incidentally, to perform two-way binding on a native HTML element, you would also need to include an annotation for the event that the radio input fires when it is selected. So if you did want to capture the changes on selection, it'd be something like checked="{{item.checked::change}}".
A couple of options:
Use paper-radio-buttons inside a paper-radio-group instead of native <input>s. These elements behave well for two-way data binding.
Listen for the change when a new item gets checked, and manually update ratings[n].checked to false for the previously selected item.
A couple more things about your code
(I don't think this is anything to do with your current problem, but it will help avoid future problems) when initializing a default value for an object or array property in a Polymer element, remember to use a function so that each element instance gets its own unique array or object. E.g.:
ratings: {
type: Array,
value: function(){
return [
{ id: 1, checked: true },
{ id: 2, checked: false }
];
}
}
Normally I think, you wouldn't want to change the values of your radio inputs. Conventionally, when the <form> containing a radio input group is submitted, the value on the radio input that is currently checked gets included with the form data, and the other radio input values are ignored. Here's an example on W3Schools. So instead of value="{{item.checked}}", something like value="[[item.data]]".
So the whole thing might be something like
class CustomInputComponent extends PolymerElement {
static get properties () {
return {
ratings: {
type: Array,
value: function(){
return [
{ id: 1, checked: true, value: 'pie' },
{ id: 2, checked: false, value: 'fries' },
{ id: 3, checked: false, value: 'los dos' }
];
}
},
selected: {
// type: Number or Object, idk
// Keep track of the selected <input>
}
};
}
static get template() {
return html`
<p>do you want pie or fries?</p>
<div id="mydiv">
<template is="dom-repeat" items="{{ratings}}">
<input
type="radio"
name="testgroup"
id="[[item.id]]"
value="[[item.value]]"
checked="{{item.checked::input}}"
on-change="radioChanged"
>[[item.value]]
</input>
</template>
</div>
`;
}
radioChanged(event){
// update ratings[n].checked for selected input
// set selected input to currently selected input
}
}

Categories

Resources