ng-model taking for all inputs after clicking edit - html

I am using AngularJS. I am generating pipeline-like structure. At first onload I am having one default ng-repeat value. After clicking "add more" I am displaying another list. It goes on adding as long as I am clicking the "add" button.
Here is my HTML:
Add button
<button data-ng-click="addNew()">Add New Workboard</button>
New pipeline will be created with Pipeline Names and one text box to add stageNames
<div data-ng-show="listOfLists.length > 0">
<div data-ng-repeat="list in listOfLists">
<div data-ng-repeat="pipeline in workboardstages track by $index">
<div class="added-eachboard">
<div class="form-group">
<input name="pipelineName" id="pipelineName" data-ng-
model="pipeline.pipelineName" type="text">
</div>
<ul class="simpleDemo workboard-drags" data-ng-repeat="(key,
workboardlist) in pipeline.workBoardStageMap">
<li data-ng-if="pipeline.pipelineName == key" ng-repeat="workboard in
workboardlist">{{workboard.stageName}}
<a href ="javascript:void(0)" data-ng-
click="editWorkboardStage(workboard.stageId)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
</li>
</ul>
<div>
<p class="weak">Stage Name:</p>
<div class="form-group">
<input name="stageName" id="stageName" data-ng-
model="newworkboard.stageName" type="text">
</div>
</div>
</div>
</div>
</div>
</div>
Controller.js
$scope.listOfLists = [];
$scope.workboardStagesWithDefault = [
{
Name:"Test"
},
{
Name:"Test2"
},
{
Name:"Test3"
}
];
$scope.addNew = function(){
var clonedList = angular.copy($scope.workboardStagesWithDefault);
$scope.listOfLists.push(clonedList);
};
$scope.editWorkboardStage = function(stageId){
AccountService.editWorkboardStage(stageId).then(function(response){
$scope.newworkboard = response.data;
});
}
$scope.getAllWorkboardStages = function(){
AccountService.getAllWorkboardStages().then(function(response){
$scope.workboardstages = response.data;
$scope.listOfLists.push($scope.workboardstages);
});
}
After clicking edit i am displaying stage name in that particular text box.But the problem is it is displaying same for neighbouring pipeline also.I want to display only for that current pipeline.As i am displaying using ng-model it is taking for all pipelines.How to display the value only for that particular pipeline?

So, the problem is related to indexing. I made $scope.newworkboard index wise.
This is the solution: (newworkboard is based on pipeline index and pass index from editWorkboardStage function.)
<input name="stageName" id="stageName" data-ng-model="newworkboard[$index].stageName" type="text">
AND
<a href ="javascript:void(0)" data-ng-click="editWorkboardStage(workboard.stageId, $parent.$parent.$index)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
HTML
<div data-ng-show="listOfLists.length > 0">
<div data-ng-repeat="list in listOfLists">
<div data-ng-repeat="pipeline in workboardstages track by $index">
<div class="added-eachboard">
<div class="form-group">
<input name="pipelineName" id="pipelineName" data-ng-
model="pipeline.pipelineName" type="text">
</div>
<ul class="simpleDemo workboard-drags" data-ng-repeat="(key,
workboardlist) in pipeline.workBoardStageMap">
<li data-ng-if="pipeline.pipelineName == key" ng-repeat="workboard in
workboardlist">{{workboard.stageName}}
<a href ="javascript:void(0)" data-ng-
click="editWorkboardStage(workboard.stageId, $parent.$parent.$index)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
</li>
</ul>
<div>
<p class="weak">Stage Name:</p>
<div class="form-group">
<input name="stageName" id="stageName" data-ng-
model="newworkboard[$index].stageName" type="text">
</div>
</div>
</div>
</div>
</div>
</div>
Controller
In the controller make an array of newworkboard and assign response.data index wise.
$scope.newworkboard = [];
$scope.editWorkboardStage = function(stageId, index){
AccountService.editWorkboardStage(stageId).then(function(response){
$scope.newworkboard[index] = response.data;
});

Related

How can I make my list save even after the page is reloaded

this is my whole thing I just want my comments to help Please.
<!DOCTYPE html>
<html>
<head>
<title>Forum</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="pixel">
<br>
<br>
<div class="blackBox">
<p class="white">| <a class="white" href="file:///home/chronos/u-885ea83f13a0b735b4185df5cf6edb6dafb04e43/MyFiles/HTML%20Final/index.html">Home</a> | <a class="white" href="file:///home/chronos/u-885ea83f13a0b735b4185df5cf6edb6dafb04e43/MyFiles/HTML%20Final/textboxPhase.html">Textbox Phase</a> | <a class="white" href="file:///home/chronos/u-885ea83f13a0b735b4185df5cf6edb6dafb04e43/MyFiles/HTML%20Final/breakoutPhase.html">Breakout Phase</a> | <a class="white" href="file:///home/chronos/u-885ea83f13a0b735b4185df5cf6edb6dafb04e43/MyFiles/HTML%20Final/goatPhase.html">Goat Cage Phase</a> | <a class="white" href="file:///home/chronos/u-885ea83f13a0b735b4185df5cf6edb6dafb04e43/MyFiles/HTML%20Final/forum.html">Forum</a> |</p>
</div><br>
<br>
<h1>Welcome to The "There is no Game" Forum</h1>
<div class="container">
<h2>Leave us a comment</h2>
<form>
<textarea id="" placeholder="Add Your Comment" value=" "></textarea>
<div class="btn">
<input id="submit" type="submit" value="Comment"> <button id="clear">Clear</button>
</div>
</form>
<div class="comments">
<h2>Comments</h2>
<div id="comment-box">
<ul>
<li>WELCOME</li>
</ul>
</div>
</div>
</div>
<script type="text/javascript">
const field = document.querySelector('textarea');
const backUp = field.getAttribute('placeholder')
const btn = document.querySelector('.btn');
const clear = document.getElementById('clear')
const submit = document.querySelector('#submit')
// const comments = document.querySelector('#comment-box')
const comments = document.getElementById('comment-box');
// array to store the comments
const comments_arr = [];
// to generate html list based on comments array
const display_comments = () => {
let list = '<ul>';
comments_arr.forEach(comment => {
list += `<li>${comment}<\/li>`;
})
list += '<\/ul>';
comments.innerHTML = list;
}
clear.onclick = function(event){
event.preventDefault();
// reset the array
comments_arr.length = 0;
// re-genrate the comment html list
display_comments();
}
submit.onclick = function(event){
event.preventDefault();
const content = field.value;
if(content.length > 0){ // if there is content
// add the comment to the array
comments_arr.push(content);
// re-genrate the comment html list
display_comments();
// reset the textArea content
field.value = '';
}
}
</script><br>
<br>
<br>
<div class="as-console-wrapper">
<div class="as-console"></div>
</div>
</div>
</div>
</body>
</html
I know this code works but every time I reload it the comments disappear and I want it to save and all the code is too complex for my new code brain to understand. This is for my website and it's a basic wiki on how to beat there is no game, the old one. I need to turn this into my professor and wanted to add something extra but I want it so if I publish this the comment section isn't just a stupid gimmick.

How to mark cloned form from inline as deleted so Django knows what to save and what not to save

views.py:
def device_add(request):
if request.method == "POST":
device_frm = DeviceForm(request.POST)
dd_form = DeviceDetailForm(request.POST)
di_formset = inlineformset_factory(Device, DeviceInterface, fields=('moduletype', 'firstportid', 'lastportid'),widgets={ 'firstportid':TextInput(attrs={'placeholder': 'e.g. TenGigabitEthernet1/0/1'}), 'lastportid':TextInput(attrs={'placeholder':'eg. TenGigabitEthernet1/0/48'})},extra=1,max_num=3, can_delete=False)
di_form=di_formset(request.POST)
if device_frm.is_valid():
# Create and save the device
# new_device here is the newly created Device object
new_device = device_frm.save()
if dd_form.is_valid():
# Create an unsaved instance of device detail
deviceD = dd_form.save(commit=False)
# Set the device we just created above as this device detail's device
deviceD.DD2DKEY = new_device
deviceD.save()
if di_form.is_valid():
deviceI=di_form.save(commit=False)
print(deviceI)
for instances in deviceI:
instances.I2DKEY=new_device
instances.save()
return render(request, 'interface/device_added.html',{'devices':Device.objects.all()})
return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
else:
device_frm = DeviceForm()
dd_form = DeviceDetailForm()
di_formset = inlineformset_factory(Device, DeviceInterface, fields=('moduletype', 'firstportid', 'lastportid'), widgets={ 'firstportid':TextInput(attrs={'placeholder': 'e.g. TenGigabitEthernet1/0/1'}), 'lastportid':TextInput(attrs={'placeholder':'eg. TenGigabitEthernet1/0/48'})},extra=1, max_num=3, can_delete=False)
di_form=di_formset(queryset = DeviceInterface.objects.none())
return render(request,'interface/device_add.html',{'form':device_frm, 'dd_form': dd_form, 'di_form':di_form})
HTML:
{{di_form.management_form}}
<div id = "rowAddition">
{% for form in di_form %}
<div>
<div class="row">
<div class="col-md-2">
<div class="form-group">
<label for="{{di_form.moduletype.id_for_label}}">Module Type<span
class="text-danger">*</span></label>
{{form.moduletype}}
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="{{di_form.firstportid.id_for_label}}">First Port ID<span
class="text-danger">*</span></label>
{{form.firstportid}}
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="{{di_form.lastportid.id_for_label}}">Last Port ID <span
class="text-danger">*</span></label>
{{form.lastportid}}
</div>
</div>
</div>
</div>
{%endfor%}
<div id="empty-form" style="display: none;">
<div class="row">
<div class="col-md-2">
<div class="form-group">
<label for="{{dd_form.moduletype.id_for_label}}">Module Type<span
class="text-danger">*</span></label>
{{di_form.empty_form.moduletype}}
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="{{di_form.firstportid.id_for_label}}">First Port ID<span
class="text-danger">*</span></label>
{{di_form.empty_form.firstportid}}
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="{{di_form.lastportid.id_for_label}}">Last Port ID <span
class="text-danger">*</span></label>
{{di_form.empty_form.lastportid}}
</div>
</div>
<div class="col-md-1">
<div class="form-group">
<div class="text-sm-center">
<br />
<button type="button" class="btn btn-outline-danger btn-rounded"
id="removerow" style="display: none;" data-toggle="modal"><i class="dripicons-
minus" ></i></button>
</div>
</div>
</div>
<!--more rows-->
<div id='morerows'></div>
Script:
let changeFlag=0;
let maxrow = $('#id_deviceinterface_set-MAX_NUM_FORMS').attr('value');
let totalForms = $('#id_deviceinterface_set-TOTAL_FORMS').val();
console.log(maxrow)
console.log(totalForms)
$('#deleteConfirmation').modal('hide');
function portidChange(val) {
changeFlag = 1;
if (val =="")
changeFlag = 0;
}
$('#addrow').click(function () {
let totalForms = $('#id_deviceinterface_set-TOTAL_FORMS').val();
console.log(totalForms)
$('#empty-form #removerow').css('display','block');
let wholerowclone = $('#empty-form').clone();
$('#morerows').append(wholerowclone.html().replace(/__prefix__/g, totalForms));
$('#id_form-TOTAL_FORMS').attr('value', (parseInt (totalForms))+1);
changeFlag=0;
if(totalForms==maxrow) {
$('#addrow').attr("disabled", true);
$('#addrow').attr("class","btn btn-rounded btn-danger");
$('#addrow i').attr("class","");
$('#addrow').html("Reached max limit");
}
})
$(document).on('click', '#removerow', function () {
let totalForms = $('#id_deviceinterface_set-TOTAL_FORMS').val();
console.log(totalForms + " total forms");
let actualformcount = totalForms-1;
if(changeFlag==1) {
console.log("changeFlag=1");
$('#removerow').attr('data-target', '#deleteConfirmation')
$('#deleteConfirmation').modal('show');
$('#removerowConfirmed').click(function () {
console.log("clicked")
$('#removerow').closest('#morerows.row').remove();
$('#deleteConfirmation').modal('hide');
if(actualformcount < maxrow) {
$('#addrow').attr("disabled", false)
$('#addrow').attr("class","btn btn-outline-success btn-rounded")
$('#addrow i').attr("class","dripicons-plus")
$('#addrow').html("+")
}
})
}
else {
console.log("ChangeFlag 0");
$('#id_deviceinterface_set-TOTAL_FORMS').attr('value', (parseInt (totalForms))-1);
$(this).closest('#morerows .row').remove();
if(actualformcount < maxrow){
$('#addrow').attr("disabled", false)
$('#addrow').attr("class","btn btn-outline-success btn-rounded")
$('#addrow i').attr("class","dripicons-plus")
$('#addrow').html("+")
}
}
});
I have this set of codes that is intended to control the number of form created from inline using a button. This is working out perfectly well. But when it comes to saving, if i were to delete something. I can only delete the last cloned row and all the rest of the data which is not deleted are saved. But if i delete a cloned row that is in the middle, the data saved goes haywire. For example my code allow cloning of 3 times. So with clone + original = 4. If i were to delete a row in the middle. Lets say row 1(1st clone). It saves the original(correct), never save the 1st clone (correct), saves the 3rd row (correct) and somehow last row data is lost. Can anyone advise me what to do? I have been stuck here for 3 days already.
One more problem: Notice this a few days ago. Because i set the view to refresh the page with the details if any field is key in wrongly, any cloned rows with the - button disappears. Can anyone explain to me why is this happening?

Vue, changing the name of an input via list item click

I have an input that I'm using in relation two an unordered list with two list items, which is in place, but I"m trying to figure out how I can change the input name/id with the click of one of the list items.
The items are not links or buttons, so I just want to be able to click the item text and if 'Public' is clicked, the input name would become public, if 'Internal' is clicked I would want the input name to be internal
I'm using Vue which may have some better options, but basically I just want to send the name of the input later on in an ajax call and I only want the name to be determined by the click of a list item potentially with a default.
What is the best way to achieve this with Vue being used?
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li>Public</li>
<li>Internal</li>
</ul>
</div>
<div>
<input type="text" name="public">
</div>
</div>
</div>
First step: use component data to your advantage
You can simply store the desired input name attribute in the component data, e.g. inputName. Then, use v-on to bind a click event listener to your elements, so that whenever they are clicked, you invoke a method that updates the inputData property of your component.
new Vue({
el: '#app',
data: {
inputName: '',
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li v-on:click="setInputName('public')">Public</li>
<li v-on:click="setInputName('internal')">Internal</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Better: Use v-for to generate list items dynamically
If you don't want the manually provide the argument to the method, there's an easier way: you simply create a list of allowed names in the component data, too, and use v-for to generate the list dynamically:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: ['Public', 'Internal']
},
methods: {
setInputName(str) {
this.inputName = str.toLowerCase();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName)">
{{ allowedName }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Even better: if there is no one-to-one correspondance between list item text and the desired name attribute
This can be useful in the case when, for example, you want the text to read Public but the name attribute to be another value. Instead of an array of strings, you can use an array of objects:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: [{
label: 'Public (or any other arbitrary text you like)',
name: 'public'
}, {
label: 'Internal (or any other arbitrary text you like)',
name: 'internal',
}]
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName.name)">
{{ allowedName.label }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>

Angular html not loading properly

Sorry if this has a really obvious answer, I'm fairly new to Angular JS and this is something that I have been stuck on for an annoyingly long time.
To give you a bit of background, I am calling ng-repeat on a directive as follows:
<div ng-controller = 'salesctrl'>
<salecell ng-repeat = "kpi in kpis" kpi ="kpi"></salecell>
</div>
With the directive being described as follows:
.directive("salecell", function(){
return{
templateUrl: "sale-cell-template.html" ,
restrict: 'E',
scope: {
kpi: '='
},
link: function(scope){
return scope;
},
controller: function($scope){
if(typeof $scope.kpi != 'undefined'){
$scope.kpi.value = 0;
$scope.increment = function(){
$scope.kpi.value++;
}
$scope.decrement = function(){
if($scope.kpi.value != 0){
$scope.kpi.value--;
}
}
}
}
};
})
and the attached controller:
.controller("salesctrl", function($scope, $rootScope, SalesSvc){
SalesSvc.query().$promise.then(function(data){
$scope.kpis = data;
});
$scope.submit = function(){
SalesSvc.save($scope.kpis).$promise.then(function(){
for(var i = 0; i < $scope.kpis.length; i++){
$scope.kpis[i].value = 0;
}
});
$rootScope.$emit('salecreate');
}
})
The issue that I am having is that, regardless of the contents of my associated template, only the outer element is being rendered. For example if I have:
<tr>
<div class="col-md-6"> <label class="control-label">{{kpi.title}}</label></div>
<div ng-show="!kpi.dollar" class="col-md-6">
<div id="spinner4">
<div class="input-group" style="width:150px;">
<div class="spinner-buttons input-group-btn">
<button ng-click="decrement()" type="button" class="btn spinner-up btn-warning">
<i class="fa fa-minus"></i>
</button>
</div>
<input ng-model="kpi.value" type="text" class="spinner-input form-control" maxlength="3" >
<div class="spinner-buttons input-group-btn">
<button ng-click="increment()" type="button" class="btn spinner-down btn-primary">
<i class="fa fa-plus"></i>
</button>
</div>
</div>
</div>
</div>
<div ng-show="kpi.dollar" class="col-md-6">
<div class="input-group m-bot15" style="width: 150px;">
<span class="input-group-addon">$</span>
<input ng-model="kpi.value" type="text" class="form-control">
</div>
</div>
Nothing will load on the page, and likewise, if I have:
<tr>
<h1> Hello World! </h1>
</tr>
Nothing is loaded either.
Things I have already checked:
-I have made sure that both $scope.kpis and $scope.kpi are defined
-I have ensured that the template is actually being called (both by inspecting elements and by calling a console.log from within the template)
-A bit of searching around suggested that it might be an error within the template, but this seems strange given that it doesn't work even with a near-empty template.
The only other thing that I can think to add is that when I was using console.log in the template that was visible in the element inspector (Chrome), but nothing else has been.
Let me know if you need anything else, and once again I hope this isn't something really stupid that I have missed.
Ensure that the content inside the table are wrapped in <td> tags. Currently they are directly inside <tr> tags and is invalid HTML.
<tr>
<td>
<div class="col-md-6"> <label class="control-label">{{kpi.title}}</label></div>
...
</td>
</tr>

Knockout Clone Whole Item In foreach

I am trying to clone elements when clicking a button. I was trying to use ko.toJS. On page load it works fine, but when I want clone the items, it is unable to bind the items (like, value, Text, etc.).
Here is the HTML:
<div class="stockItems-inner" data-bind="foreach: StockItems">
<div data-bind="if: Type=='Input'">
<div class="stock_container_input">
<input type="text" data-bind="value: Value" />
</div>
</div>
<div data-bind="if: Type=='Radio'">
<div class="stock_container_control">
<div data-bind="foreach: Options">
<div class="stockLbl">
<input type="radio" data-bind="text: Text, checked:$parent.Value, attr:{'id':Id, 'name': $parent.Text, 'value': Value}" />
<label data-bind="attr:{'for':Id}, text: Text"></label>
</div>
</div>
</div>
</div>
</div>
<div class="addItem">
<button type="button" data-bind="click: CloneItem"><img src="images/add.png" alt="" /></button>
</div>
The View Model:
ConfigurationStockViewModel = function() {
var self = this;
this.StockItems = ko.observableArray();
this.ApplyData = function(data){
self.StockItems(data.Items);
}
this.CloneItem = function(StockItems){
self.StockItems.push(ko.toJS(StockItems));
};
};
When clicking the button, an error is thrown: Unable to process binding. I am using JSON data for binding.
Not exactly sure what end result you want without working code, but sounds like you want to clone the last item in array and add to array?
If so, I think you have an error - your add button click binding will never pass anything to the function you defined, since it is outside the foreach. You need something like this:
this.CloneItem = function() {
var toClone = self.StockItems()[self.StockItems().length - 1]
self.StockItems.push(toClone);
};
Here is a simplified example without radio buttons, etc:
http://jsfiddle.net/5J47L/