Use v-for key outside of the loop - javascript

I have a simple v-for that renders a list of items inside a select box like this:
<div class="col-md-4">
<select class="form-control" v-model="tableStyle">
<option v-for="(item,key) in tableStyles">
{{ item }}
</option>
</select>
</div>
Then I have a button that should remove a specific item, the selected one. I want to access its key so I can remove it easily. How can I do that? At the moment my key is undefined. Can I use v-model for that?
<button #click="removeStyle(key)" class="btn btn-default btn-xs">
<span class="glyphicon glyphicon-remove text-danger"></span>
</button>

When an option is selected from the select element, and it has v-model binded to something (tableStyle in your case) the value attribute of the selected option element will be assigned there. So, you can bind value to the key:
<select class="form-control" v-model="tableStyle">
<option v-for="(item,key) in tableStyles" v-bind:value="key">
{{ item }}
</option>
</select>
And then you can use your tableStyle:
<button #click="removeStyle(tableStyle)" class="btn btn-default btn-xs">
<span class="glyphicon glyphicon-remove text-danger"></span>
</button>
Working example: https://jsfiddle.net/hy21um75/

I check your code and it is just incomplete. For that reason, I want to give some clarifications to improve your understanding about how a Vue instance works.
First, remember that the HTML tag select uses the option tag for each item of the tableStyles. Now, this option tag should has a value parameter and a text like in this structure:
<select>
<option value="0">Style 01</option>
...
<option value="3">Style 04</option>
</select>
Now, what we need is a way of assigning each key of the array tableStyles to each parameter value of the option tag and rendering the style name of the array tableStyles as the text of the option tag.
<option v-for="(item, key) in tableStyles" :value="key">
{{item}}
</option>
Also, do not forget about v-model directive, which creates two-way data bindings on form elements. This means, it automatically picks the correct way to update the element based on the input type. We can achieve this by adding selected to the data definition in the Vue instance creation and addingv-model="selected" to the select tag.
Ok Teocci, but why I got undefined for my parameter key called in the onClick event in the button tag?
Well that is because key only is defined inside of the v-for scope and this scope is defined by the option tag.
Then, how can I get the selected key out of the v-for scope?
Easy, just use selected that is defined in all the scope of the selector tag as shown in this snippet:
new Vue({
el: '#selector',
data: {
selected: '',
tableStyles: ['Style 01', 'Style 02', 'Style 03', 'Style 04'],
},
methods: {
removeStyle: function(key) {
this.tableStyles.splice(key, 1);
},
},
});
#selector .main{
float: left;
padding-left: 50%;
padding: 0px 0px 0px 16px !important;
border: none;
vertical-align: middle;
height: 48px;
line-height: 48px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="selector">
<div class="main">
<select class="form-control" v-model="selected">
<option v-for="(item, key) in tableStyles" :value="key">
{{ item }}
</option>
</select>
</div>
<div class="main">
<button #click="removeStyle(selected)" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-remove text-danger">Remove</span></button>
</div>
<div class="main">
<span>Selected: {{ selected }}</span>
</div>
</div>

Related

How to remove and add dropdown values based on the condition selected by another dropdown in angular?

My requirement:
I have to create a form row that has two select dropdowns and add and delete button at last
1. the first dropdown will have a list of values for ed.. ['one', 'two', 'three','four']
2. the second dropdown will have the condition ['and','or']
let say the first row of the form value selected like ['one'] ['and'] then clicking on the add button then the second row will create. here first dropdown should not show the 'one' value because the condition is 'and'. if user select or then it should all the values. similary for all the rows i have to create logic in angular.
HTML Code:
<div class="state-filter-conditions-grid subs-model-sec filter-grid" *ngFor="let filterCondition of filters; index as i">
<!-- OUTPUT PROPERTY -->
<ng-container *ngTemplateOutlet="filterView == 'subscription'? attrs: map; context: { index: i }"></ng-container>
<!-- CONNECTOR CONDITION -->
<div class="dt-attr valueCondition ctrl-condition minimal">
<div class="abs-cheveron select-box-cheveron">
<select class="state-select" [(ngModel)]="filters[i].op">
<option *ngFor="let val of op" [value]="val">{{val}}</option>
</select>
</div>
</div>
<!-- INPUT -->
<ng-container *ngTemplateOutlet="filterView != 'subscription'? attrs: map; context: { index: i }"></ng-container>
<!-- SELECT -->
<div class="dt-attr icons center-align">
<select class="ctrl-condition" *ngIf="!(i==filters.length-1)" [(ngModel)]="filters[i].logop" (change)="operatorChange(filters[i])">
<option *ngFor="let val of logop" [value]="val">{{val}}</option>
</select>
</div>
<!-- ICONS -->
<div class="dt-attr icons center-align">
<button *ngIf="i==filters.length-1" class="add-btn" (click)="addStateConditionRow()"><i
class="fa fa-sm fa-plus add-icon" aria-hidden="true"></i></button>
<button *ngIf="i>0" class="delete-btn" (click)="deleteStateConditionRow(i)"><i
class="fa fa-sm fa-trash delete-icon"></i></button>
</div>
</div>
<ng-template #attrs let-i="index">
<div class="dt-attr ">
<ng-container *ngIf="!dataProps">
<input class="ctrl-attr" type="text" [(ngModel)]="filters[i].value">
</ng-container>
<ng-container *ngIf="dataProps">
<select class="value-select" [(ngModel)]="filters[i].value">
<option *ngFor="let data of dataProps" [value]="data.attrId">{{data.attrName}}</option>
</select>
</ng-container>
</div>
</ng-template>
<ng-template #map let-i="index">
<div class="dt-attr ctrl-condition minimal">
<input class="ctrl-attr" type="text" clickOutside (clickOutside)="closeAccordion($event)" (click)="openAccordion($event)" [(ngModel)]="filters[i].attribute">
<div *ngIf="showAccordion" class="state-filter-accordion" style="position: absolute;
top: 105%;
width: 100%;z-index:1">
<app-common-accordion-mapping [filterInputRef]="filterInputRef" [inputAttributes]='inputAttributes' ></app-common-accordion-mapping>
</div>
</div>
</ng-template>
can you guys help me to achieve this.
Thanks in advance.
I think what you are looking for is to dynamically populate dropdown based on a particular logic. This stackoverflow answer covers that for AngularJS and a stackoverflow question + blog for Angular 8 . However I cannot help you with the business logic itself as it is not clear to me.

Make first value in dropdown bold in angular js

I have a dropdown where I need to make first value in the dropdown to be bold.Dropdown code is as follows.
<div class="col-xs-3">
<select-box id="ad-version-select" options="curItem.stats.version" model="state.version" initial="All" change="watchvalue()" ng-disabled="state.partialDisable"></select-box>
</div>
<select class="form-control" ng-model="model" ng-change="change()">
<option ng-if="initial.length" ng-bind="initial" value=""></option>
<option ng-repeat="option in options" value="{{getValue()}}" ng-selected="model==getValue()" ng-bind="getTitleVariable()"></option>
</select>
I tried like
<style>
div.col-xs-3>div:first-child {
font-weight: bold;
}
</style>
but didn't worked. I am not getting any idea how to make only the first value bold. I can't use jquery. Can someone help me with this?
There need to be an alteration done in your css selector. You should select the first child of the option to make it bold.
option:first-child
{
font-weight: bold;
}
Here is the sample Fiddle
Hope this helps.
-Help :)
You can use ng-options with ng-class:
<select ng-model="Blah">
<option ng-repeat="person in persons" ng-class="{red: person.id == 1}" ng-selected="{Blah == person.Name}">{{person.Name}}</option>
</select>
app.controller('AppController',
[
'$scope',
function($scope) {
$scope.persons = [
{id: 1, Name:'John',Eligible:true},
{id: 2,Name:'Mark',Eligible:true},
{id: 3,Name:'Sam',Eligible:false},
{id: 4, Name:'Edward',Eligible:false},
{id: 5, Name:'Michael',Eligible:true}
];
$scope.Blah = 'Sam';
}
]);
Here is the Plunker
#Help's solution should work.
But not all browsers support styles in <select><option>. Maybe you need to build the component by yourself, something like this:
<div class="select">
<div class="selected" ng-bind="current.title"></div>
<div class="options">
<div class="option" ng-repeat="option in options" value="{{option.value}}" ng-bind="option.title" ng-click="current=option"></div>
</div>
</div>
.option:first-child {font-weight: bold;}
You'll need to add some more scripts and styles to make it work like a natural <select>.

how to show/hide div based on drop down selection using angular?

i want to show and hide a div based on selection from the drop down , here is my code, this is my html code for dropdown which fetches the values from the "selectItemsFilterCriteria" json structure
<select ng-model="appointment" ng-change="changeme()" ng-options="item.name for item in selectItemsFilterCriteria">
<option ng-option value="" >Filter Criteria</option>
</select>
this is my changeme() function created inside a controller
$scope.changeme = function() {
$scope.appointment = $scope.items[0];
}
this is code for my div that is to be show or hide , right now my code is working on selection of first option from drop down it is showing me the div but the problem is that its not hiding that div on the selection of any other option from the dropdown list, kindly tell me where i m doing wrong??
<div class="mycontainer" ng-show=appointment >
<div class="left-nav">
<accordion close-others="true">
<accordion-group ng-repeat="item in pagedItems[currentPage] |filter:{name:item.name}| orderBy:sortingOrder:reverse">
<accordion-heading>
<table>
<tr class="odd" ng-click="showDataDetail=!showDataDetail" style="cursor: pointer">
<td><p class="lead-name">{{item.name}}</p>
<p class="call-up-icon">{{item.phoneNo}} </p>
<p>Lead Date : 07/02/2015</p></td>
<td><p></p>
<p class="blue-txt">{{item.trade}}</p>
<p class="fl cstm-wdth">GNU09</p>
<p class="fl">{{item.time}}</p>
<div class="cb"></div>
</td>
<td><p>Today</p>
<p>C#SQL</p>
<p class="blue-remark-icon"></p></td>
</tr>
</table>
</accordion-heading>
<div>{{item.data}}</div>
</accordion-group>
</accordion>
</div>
</div>
items array:
$scope.selectItemsFilterCriteria = [
{id:1 , name:"Appointments Scheduled"},
{id:2 , name:"fresh leads"}
];
Basically the problem is with your ng-change function call,
$scope.changeme = function() {
$scope.appointment = $scope.items[0];
}
You are setting appointment to first value of items array. Hence whenever you change the options, the function sets it back to first option , in turn the div is shown.
Please remove the ng-change function and try.
Remove the $scope.changeme() function. It is not necessary.
Since you are using ng-model on select whatever option you select will get assigned to the ng-model i.e appointment in your case.
Here is the plunkr example

Editing property from Object in ng-repeat from LocalStorage

I'm listing an array of objects saved into Localstorage in a table-like layout.
Each row displays data saved in a particular object. I want to be able to edit and update certain properties from the object once it has already been saved into LocalStorage.
This is how a couple of my objects looks like:
[{
"date":"2014 10 16",
"time":"20.22",
"car":"396",
"driver":"Seb",
"from":"A",
"destination":"B",
"pax":"3",
"arrival":"23.10"
},
{
"date":"2014 10 16",
"time":"23.22",
"car":"46",
"driver":"Eric",
"from":"C",
"destination":"E",
"pax":"3",
"arrival":"00.10"
}]
So far my frontend code displaying the Destination property looks like this:
HTML
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">{{record.destination}}</div>
// Shows current value
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
// Shows select with options to be picked to update property
<div class="col-md-1">
<button ng-click="editItem = !editItem"
ng-show="!editItem">Edit</button>
<button ng-click="editData(record); editItem = !editItem"
ng-show="editItem">Ok</button>
</div>
//Toggles between current value and select and triggers editData function
Relevant JS:
$scope.editData = function (record) {
record.destination = $scope.locationList2;
jsonToRecordLocalStorage($scope.recordlist);
}
So far when I trigger editData it just deletes the Destination property, it doesn't update it with the model of locationList2 from the Select.
What am I missing?
EDIT
Here's the complete ng-repeat piece of code:
<div class="row msf-row" ng-repeat="record in recordlist | filter: search">
<div class="col-md-1">{{record.time}}</div>
<div class="col-md-1"><strong>{{record.car}}</strong></div>
<div class="col-md-1">{{record.driver}}</div>
<div class="col-md-3">{{record.from}}</div>
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">
{{record.destination}}
</div>
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
<div class="col-md-1">{{record.pax}}</div>
<div class="col-md-1">
<button
ng-click="editItem = !editItem"
ng-show="!editItem">
<i class="fa fa-pencil"></i>
</button>
<button
ng-click="editData(record); editItem = !editItem"
ng-show="editItem">
<i class="fa fa-check"></i>
</button>
</div>
</div>
Also, I here's a Plunkr to ilustrate the issue!
Add a driver, car code and location before starting to see the app running and the mentioned problem.
You could use angular-local-storage as an abstraction over LocalStorage API.
If you want to just hack it, you can do something along localStorage.setItem('data', JSON.stringify(data)) when setting data and use JSON.parse(localStorage.getItem('data')) to extract it. LocalStorage doesn't deal with objects by default so we have to serialize it.
Regardless of the solution you choose, it could be a good idea to extend your edit a bit:
$scope.editData = function (recordlist) {
$scope.recordlist.destination = $scope.locationList2;
// replace whole LocalStorage data here now. no need to "patch" it
updateLocalStorage('data', <data containing your objects goes here>);
}
If you have multiple ways to modify the data and want to avoid explicit update, you could set up a watcher instead:
$scope.$watch(<data name goes here>, function(newVal) {
// update your LocalStorage now
});
Why it fails with ng-repeat?
The reason you see the behavior is quite simple. $scope.locationList2 is a single variable that gets bound for each member created by ng-repeat. That explains why it stays empty during edit.
You will need to bind the data using some other way. Consider binding it directly to your record models. Example: AngularJS - Using $index in ng-options .
Solution
The original code had bits like this:
JS:
$scope.editData = function (record) {
record.destination = $scope.location;
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="location" ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
Note that the markup is inside a ng-repeat and effectively each item created by it points at the same location! This isn't good.
To make it work I changed it like this:
JS:
$scope.editData = function () {
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="record.destination" ng-options="location.place as location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
As mentioned above the JS could be replaced by a watcher. The important thing to note here is that I bind the data directly to the records. That avoid hassle at editData and more importantly gets rid of the problematic ng-model reference.

Pass array values in the function in controller

I have been working over an application for over a month now. But I am stuck at a place. The scenario is not that difficult, but I think I am missing something basic.
Scenaro: I am collecting selected values of numerous dropdownlists in an array and passing them to the controller in app.js, that would save the value in the database.
Code for html:
Note: Alert is a custom directive that would generate dropdownlists on click of "Add Projects" button.
<div ng-controller="AlertDemoCtrl">
<alert ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)" ng-model="ProjectId[item.ProjectId]">
<ul style="list-style-type: none; margin-left: 0px;">
<li >
<!--data-ng-model="selectedProject[$index]"-->
<!--data-ng-model="test.ProjectId"-->
<!--<select data-ng-model="test.ProjectId"
data-ng-options="test.ProjectId as test.ProjectName for test in items" id="Project">-->
<select>
<option value="">-- Choose a Project --</option>
<option ng-repeat="item in items" value="{{item.ProjectId}}">{{item.ProjectName}}</option>
</select>
<button type="button" ng-click="closeAlert($index)"><img src="delete.png" alt="Remove" style="height:20px; width:20px;" /></button>
</li>
</ul>
</alert>
<button class='btn' type='button' ng-click="addAlert()">Add Projects</button>
</div>
Code for app.js
var CreateCtrlEmp = function ($scope, $location, SampleEmp, SampleProj, SampleDes, sharedValues) {
$scope.items = SampleProj.query({ q: $scope.query });
$scope.itemsd = SampleDes.query({ q: $scope.query });
$scope.save = function (item) {
//$scope.item.ProjectId = new Array("5","8");
//$scope.ProjectId = new Array();
$scope.item.ProjectId = new Array(item);
alert($scope.item.ProjectId);
SampleEmp.save($scope.item);
$location.path('/emp');
};};
I want to pass on the values in the save function. When I see the values in the firebug panel. I can see that the array contians null values in it.
If I pass static values in the controller then the values are saved in the database.
Please guide.
Thanx a lot in advance.
Tushar Sharma.

Categories

Resources