Why isn't ng-repeat removing my file input types and how can I get this to work correctly? - angularjs

I have the following div to allow a user to upload multiple file inputs:
<div class="form-inline" ng-repeat="file in selectedFiles track by $index">
<input class="form-control" style="width:350px;" type="text" name="description{{$index}}" ng-model="file.fileDescription" ng-disabled="isDisabled" />
<input class="form-control" style="width:350px;" type="file" name="file_file{{$index}}" ng-model="file.file" accept="application/pdf" ng-disabled="isDisabled" />
<button ng-if="$last" class="btn btn-link" ng-click="addFile();" ng-disabled="isDisabled"><i class="glyphicon glyphicon-plus-sign text-success large-font"></i></button>
<button class="btn btn-link" ng-click="removeFile($index);" ng-disabled="isDisabled"><i class="glyphicon glyphicon-remove text-danger large-font"></i></button>
</div>
And I have the following in my scope:
scope.selectedFiles = [];
scope.addFile = function() {
scope.selectedFiles.push({});
};
scope.removeFile = function(index) {
if(index >= 0) {
scope.selectedFiles.splice(index, 1);
}
};
If I press the addFile button, it adds rows just fine. If I press the removeFile button, a line is removed, however, the file inputs still remain the same.
For example, if I press the addFile button 3 times and put in 3 files. It has all 3 lines as it should. If I then press the removeFile button on the first or second line, the second line is correct on the left, but the 3rd file input was removed, not either of the first two.
How can I get this to remove lines as I would expect it to?

I'm not sure of why it behave weird on you. It works just fine on this fiddle I made so please double check :)
I intentionally removed the track by and added examples to the code to show that it removes the one you clicked:
$scope.selectedFiles = [
{file:'File1', fileDescription: 'First file'},
{file: 'File2', fileDescription: 'Second file'},
{file: 'File3', fileDescription: 'Third file'}
];
$scope.addFile = function() {
$scope.selectedFiles.push({});
};
$scope.removeFile = function(index) {
if(index >= 0) {
$scope.selectedFiles.splice(index, 1);
}
};

Maybe try:
delete scope.selectedFiles[index];

Related

Rebind of data-ng-click not working

I am using this template and binding data with it
<div id="groupSegment" data-ng-repeat="q in CurrentQuestion">
Segment Info
<div>{{q.SegmentName}}</div>
Questions:
<div>{{q.Title}}</div><div>{{q.Description}}</div>
<input type="button" value="Previous" id="d{{q.PrevQuestIndex}}" data-ng-click="ChangeQuestion({{q.PrevQuestIndex}})" /><br /> <input id="d{{q.NextQuestIndex}}" type="button" value="Next" data-ng-click="ChangeQuestion({{q.NextQuestIndex}})" />
</div>
Issue coming that on click of Next and Previous its not updating the value of index when clicking next time.
Html shows that the updated value is there but when i am clicking then its showing the value that was set when html renderd
Here is the funtion that firing on click.
$scope.ChangeQuestion = function (index) {//this indux value not getting changed
if (index < 0 || index > $scope.Questions.length)
return;
$scope.CurrentQuestion = [];
var i = 0;
$($scope.Questions[index]).each(function () {
if (i == 0) {
$scope.CurrentQuestion.push({ Title: this.Title, Description: this.Description,SegmentName: this.SegmentName, NextQuestIndex: index + 1, PrevQuestIndex: index - 1 });
}
i++
});
$scope.$apply();
};
So how I can refresh this on click parameter
Normally I'm using ng-click instead of data-ng-click which you used..
Also You don't need to pass parameters with {{}} if you use it inside ng- tag.
Change it as ng-click="ChangeQuestion(q.PrevQuestIndex)"
<div id="groupSegment" data-ng-repeat="q in CurrentQuestion">
Segment Info
<div>{{q.SegmentName}}</div>
Questions:
<div>{{q.Title}}</div><div>{{q.Description}}</div>
<input type="button" value="Previous" id="d{{q.PrevQuestIndex}}" ng-click="ChangeQuestion(q.PrevQuestIndex)" /><br />
<input id="d{{q.NextQuestIndex}}" type="button" value="Next" ng-click="ChangeQuestion(q.NextQuestIndex)" />
</div>

how to set table row colors depending on label "yes/no" clicks per row

I have been attempting to get the following piece of code to work but have as yet no been able to find a good solution. I have succesfully done this type of functionality via jQuery but my new requirements are to figure out how to do it in an angular way.
I have a table which is contructed via ng-repeat, each row contains a set of yes/no buttons in order to "approve" or "decline" the data visible in each row. When a row is either approved or declined, the color of that row will change to either green or red.
Currently all my rows are changing colors instead of only the row where Yes/No was clicked. I have tried doing something with the index and sending through the id (term in this case) and countless other things but I am unsure what to do inside the controller and how to add the class name specific to each row. Help would be greatly appreciated.
HTML:
<tr ng-repeat="tableData in maximumOfferData" ng-class="{0:'test-none', 1:'test-yes',2:'test-no'}[classstatusmaximum]">
<td>{{tableData.term}}</td>
<td>{{tableData.offer}}</td>
<td>{{tableData.payment}}</td>
<td>{{tableData.coverage}}</td>
<td>
<div class="btn-group pull-right">
<label data-ng-model="testyes"
data-btn-radio="'Left'"
class="btn btn-default ok ng-pristine ng-untouched ng-valid"
ng-click="changeMaximumStatusYes(tableData.term)">
YES
</label>
<label data-ng-model="testyes"
data-btn-radio="'Middle'"
class="btn btn-default nok ng-pristine ng-untouched ng-valid"
ng-click="changeMaximumStatusNo(tableData.term)">
NO
</label>
</div>
</td>
</tr>
Controller.js:
$scope.maximumOfferData= [
{'term':'7', 'offer':'11500', 'payment':'11.57', 'coverage':'18' },
{'term':'8', 'offer':'12500', 'payment':'16.88', 'coverage':'24' },
{'term':'9', 'offer':'9500', 'payment':'18.72', 'coverage':'12' }
];
$scope.classstatusmaximum = "0";
$scope.changeMaximumStatusYes = function(offerid){
console.log(offerid);
if ($scope.classstatusmaximum !== "1")
$scope.classstatusmaximum = "1";
};
$scope.changeMaximumStatusNo = function(offerid){
console.log(offerid);
$scope.classstatusmaximum = offerid;
if ($scope.classstatusmaximum !== "2")
$scope.classstatusmaximum = "2";
};
See above Plunker attempt Here:
http://plnkr.co/edit/3OjtzSUWdWCYTpXqxtOd?p=preview
change this line in the html:
<tr ng-repeat="tableData in maximumOfferData"
ng-class="{0:'test-none', 1:'test-yes',2:'test-no'}[tableData.status]">
and this
<label data-ng-model="testyes"
data-btn-radio="'Left'"
class="btn btn-default ok ng-pristine ng-untouched ng-valid"
ng-click="changeMaximumStatusYes(tableData)">
YES
</label>
<label data-ng-model="testyes"
data-btn-radio="'Middle'"
class="btn btn-default nok ng-pristine ng-untouched ng-valid"
ng-click="changeMaximumStatusNo(tableData)">
NO
And in your controller:
$scope.maximumOfferData= [
{'term':'7', 'offer':'11500', 'payment':'11.57', 'coverage':'18','status':'0' },
{'term':'8', 'offer':'12500', 'payment':'16.88', 'coverage':'24','status':'0' },
{'term':'9', 'offer':'9500', 'payment':'18.72', 'coverage':'12','status':'0' }
];
$scope.changeMaximumStatusYes = function(data){
data.status = "1";
};
$scope.changeMaximumStatusNo = function(data){
data.status = "2";
};
In this way you set a different status on every line, rather than set the status on a single var

Call the first <span> in a scrollbar when press enter using angularjs

I have a text box which is using for search.When enter the characters it searches the values and shows one by one in a scrollbar. When i click on any found value it redirects to the related page but when press enter it should call first value in that scrollbar.Below is my code.
<div><input type="text" value="" placeholder="search" ng-model="searchText" name="testName" ng-keyup="search()"></div>
<div class="scroll" ng-show="searchText.length" ng-hide="!searchText.length">
<div ng-repeat="relatedData in data">
<span ng-click="showDetails(relatedData)" ng-model="searchText">{{ relatedData }} </span><br />
</div>
</div>
and below is my script code:
$scope.showDetails = function(relatedData) {
$http.get("searchInfo.json").success(function(response) {
var searchT = relatedData;
$http.get(searchT+'Details.json').success(function(response) {
$scope.details = response;
$scope.searchText = "";
});
});
}
Could you please help to call first value in multiple values scrollbar,Thanks.
One way would be to wrap your search field in a form element:
<form ng-submit="showDetails(data[0])">
<input type="text"
value=""
placeholder="search"
ng-model="searchText"
name="testName"
ng-keyup="search()">
</form>
ng-submit will catch the form submit event triggered by pressing Enter.

parsleyjs with multi steps form

I'mn creating a multi step form wizard (using Twitter Bootstrap Wizard) and looking at the Parsley multi step example I'm not sure how I would implement it if I have more then two steps my current form has at least 4 steps.
This is what I don't understand
<span class="next btn btn-info pull-right" data-current-block="1" data-next-block="2">Next ></span>
My next button is constant
Here is the parsley example
<form id="demo-form" data-parsley-validate>
<div class="first block1 show">
<label for="firstname">Firstname:</label>
<input type="text" name="firstname" data-parsley-group="block1" required/>
<label for="lastname">Lastname:</label>
<input type="text" name="lastname" data-parsley-group="block1" required />
<span class="next btn btn-info pull-right" data-current-block="1" data-next-block="2">Next ></span>
</div>
<div class="second block2 hidden">
<label for="fullname">Email:</label>
<input type="text" name="fullname" required data-parsley-type="email" data-parsley-group="block2" />
<span class="next btn btn-info pull-left" data-current-block="2" data-next-block="1">< Previous</span>
<input type="submit" class="btn btn-default pull-right" />
</div>
</form>
<script type="text/javascript">
$(document).ready(function () {
$('.next').on('click', function () {
var current = $(this).data('currentBlock'),
next = $(this).data('nextBlock');
// only validate going forward. If current group is invalid, do not go further
// .parsley().validate() returns validation result AND show errors
if (next > current)
if (false === $('#demo-form').parsley().validate('block' + current))
return;
// validation was ok. We can go on next step.
$('.block' + current)
.removeClass('show')
.addClass('hidden');
$('.block' + next)
.removeClass('hidden')
.addClass('show');
});
});
</script>
The solution or workaround is pretty simple. It's best just to use Bootstrap Wizard methods your going to want to have the following
$('#w4').bootstrapWizard({
tabClass: 'wizard-steps',
nextSelector: 'ul.pager li.next',
previousSelector: 'ul.pager li.previous',
firstSelector: null,
lastSelector: null,
onNext: function( tab, navigation, index, newindex ) {
var current = index,
next = current + 1;
// only validate going forward. If current group is invalid, do not go further
// .parsley().validate() returns validation result AND show errors
if (next > current)
if (false === $('#bioForm').parsley().validate('step' + current))
return false;
// validation was ok. We can go on next step.
$('.step' + current)
.removeClass('show')
.addClass('hidden');
$('.step' + next)
.removeClass('hidden')
.addClass('show');
}
});
I know this is late, but could help someone else in need .Had similar problem and this is how i solved it.
i added this to each control i need to validate on each steps
add this to step1 controls : data-parsley-group="block-1"
add this to step2 controls: data-parsley-group="block-2"
....keep increasing for each steps.
in your bootstrapwizard javascript add the code below in the 'OnNext' fuction.
$('#form').bootstrapWizard({
tabClass: 'wizard-steps',
'onNext': function (tab, navigation, index) {
var $valid = $("#form").parsley().validate({ group: 'block-' + index });
if(!$valid) {
return false;
}
}
});
Hope this helps you out.

Ng-model does not update view

I have searched thoroughly everywhere and can't seem to find the solution to my problem.
I am trying to make a form to fill in to create new task object onto projects on the website like a scrum backlog or something in Angular and angular-ui.
I use Angular-UI for typeahead functionality for when adding team members to a task, so available members on a project pop-up. I have seen guys with similar problems, but nothing seems to solve it for me. Below is the HTML and the controller. Sorry for the long markup, but I suspect it has to do something with nesting the controllers and mixing the scopes, so I'm including everything relevant.
<div ng-controller="SubmitCreateTaskController">
<div class="modal fade" id="taskModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title" id="myModalLabel">New Task</h4>
</div>
<div class="modal-body">
<form role="form" method="post" name="create-task">
<div class="form-group">
<label for="taskname">Task Name</label>
<input type="text" class="form-control" id="taskname" ng-model="taskForm.taskName" placeholder="Task Name">
</div>
<div class="form-group">
<label for="taskdesc">Description</label>
<textarea class="form-control" id="taskdesc" size="3" ng-model="taskForm.taskDescription" placeholder="Enter a short description here..." rows="2"></textarea>
</div>
<div class="form-group">
<label for="assigneddate">Assigned Date</label>
<input type="text" class="form-control" id="assigneddate" ng-model="taskForm.assignedDate">
</div>
<div ng-controller="TypeAheadController">
<div class="form-group">
<label for="contributors">Add Contributors</label>
<input id="contributors" type="text" class="form-control" ng-model="contrib.selected" typeahead="member for member in contrib.stream_members | filter:$viewValue"
typeahead-editable="false" typeahead-on-select="contrib.onSelect($item)">
</div>
<div class="form-group">
<label for="users">Contributors:</label>
<textarea class="form-control" disabled="disabled" id="users" ng-model="contrib.entered" rows="1"></textarea>
</div>
</div>
<div class="form-group">
<label for="taskcomments">Comments</label>
<textarea class="form-control" id="taskcomments" ng-model="taskForm.comment" placeholder="Comments" rows="2"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="taskForm.submit()">Add Task</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
</div>
</form>
</div>
</div>
</div>
</div>
Controllers:
.controller('SubmitCreateTaskController', ['$scope', '$http', function($scope, $http) {
$scope.taskForm = {};
$scope.taskForm.taskName = '';
$scope.taskForm.taskDescription = '';
$scope.taskForm.assignedDate = new Date();
$scope.taskForm.contributors = [];
$scope.taskForm.comment = '';
$scope.taskForm.submit = function(item, event) {
var formData = {name: $scope.taskForm.taskName,
description: $scope.taskForm.taskDescription,
status: 'open',
assigned: $scope.taskForm.assignedDate,
completed: null,
contributors: $scope.taskForm.contributors,
comments: [{body: $scope.taskForm.comment,
user: 'RACHE User',
date: new Date()
}]
};
var postURL = '../create_task/' + $scope.stream_name;
$http.post(postURL, formData)
.success(function(){
taskForm = {}; // empty the form of previous input values
alert('New Task Created for ' + $scope.stream_name);
})
.error(function(res) {
alert(res.data);
});
};
}])
.controller('TypeAheadController', ['$scope', '$http', function($scope, $http) {
$scope.contrib = {};
$scope.contrib.selected = '';
$scope.contrib.stream_members = undefined;
$scope.contrib.entered = [];
$http.get('/stream_members/' + $scope.stream_name)
.then(function(res) {
$scope.contrib.stream_members = res.data.stream_members;
});
$scope.contrib.onSelect = function($item) {
$scope.contrib.selected = '';
$scope.contrib.entered.push($item);
console.log($scope.contrib.entered);
};
This last bit is the important part in 'TypeAheadController'. I am trying to add the poped-up team members to a textarea just below which would be sent to the DB later. That is why I have bound the actual typeahead input box to 'contrib.select' and the "display/post" box to 'contrib.entered', so the search can be continued after adding one member, the search box is cleared, selected member is added to box below, new search can begin. In the mark up I call the last (onSelect) function in the typeahead-on-select callback. This so that I can clear the input box and another member can be easily added without deleting manually. IN this function the entered member should be appended to the array that is bound to below "display/post" box. This happens, since the console log shows good value, the search/input field gets cleared, so the function gets called as well.
The view does not get updated with the updated array bound to display box however. I have tried EVERYTHING. I have googled around and found it here that dot notation needs to be used as Angular can't update with primitives, but this hasn't helped either.
Everything works fine, the logic is good, values are good when I print them out, pop-up works and clears up as expected, but The damn textarea under it does not get updated.
Any suggestions? I have been stuck on this for almost a day now and I am really frustrated by this. I would be ever so greatfull for any help!
Thanks guys in advance!
Textarea do use the value attribute, your code isn't working because contrib. entered isn't between the tags, but because you can not bind the textarea to an array (it needs to bind to a string).
look at this plunker, if you do this in your html:
<textarea class="form-control" disabled="disabled" id="users" rows="1" ng-model="contrib.enteredString"></textarea>
and add this line at the end of your typeahead controller:
$scope.contrib.enteredString = $scope.contrib.entered.toString();
then the text area will update
Textareas don't use the ng-value as their value is contained within the tag. Remove the ng-model and put the value between the tags.
<textarea class="form-control" disabled="disabled" id="users" rows="1">{{contrib.entered}}</textarea>

Resources