I am trying to test my Angular 2 Template but doing something incorrect as I don't get any filteredFirms to repeat through.
Here is my directive controller code:
(my actual firm service is just getting a dummy json file and return an array of firm objects, but I'm not testing my service here so I'm mocking this call as you can see in my spec file below.)
export class FirmListComponent implements OnInit {
constructor(public firmService: FirmService) { }
public ngOnInit() {
this.firmService.stateObservable.subscribe((state) => {
this.firms = state.firms;
this.filteredFirms = this.firms;
});
this.getFirms();
}
public getFirms(value?: string) {
this.loading = true;
this.firmService.getFirms(value).subscribe((response: any) => {
this.loading = false;
});
}
}
}
My directive template:
<thead>
<tr>
<th class="checkbox-col">
<md-checkbox [(ngModel)]="selectAll" (click)="selectAllChanged()" aria-label="Select All"></md-checkbox>
</th>
<th>
Firm Name
</th>
<th>
Country
</th>
<th>
Industry
</th>
<th>
EDF
</th>
<th>
LGD
</th>
<th>
Modified
</th>
<th>
Modified By
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let firm of filteredFirms; let i = index" class="animate-repeat" [ngClass]="{'active': firm.selected}">
<td class="checkbox-col">
<md-checkbox [(ngModel)]="firm.selected" aria-label="firm.name" (change)="selectFirm(i)"></md-checkbox>
</td>
<td>{{firm.name}}</td>
<td>{{firm.country}}</td>
<td>{{firm.industry}}</td>
<td>
<span class="label bg-purple600">US 4.0</span>
<span class="label bg-green600">US 4.0</span>
</td>
<td>
<span class="label bg-pink800">US 4.0</span>
<span class="label bg-orange300">US 4.0</span>
</td>
<td>{{firm.modifiedOn}}</td>
<td>{{firm.modifiedBy}}</td>
</tr>
</tbody>
My tests for the table head portion pass just fine, but I don't get any rows when I try to test the table body.
My spec file testing the template:
describe('Firm List Component', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MaterialModule, FormsModule, AppModule],
declarations: [FirmListComponent],
providers: [FirmService]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(FirmListComponent);
component = fixture.componentInstance;
debugEl = fixture.debugElement;
element = fixture.nativeElement;
firmService = fixture.debugElement.injector.get(FirmService);
// mockFirms is just an array of objects with firm data
getObservableSpy = spyOn(firmService, 'stateObservable')
.and.returnValue(mockFirms);
getFirmsSpy = spyOn(firmService, 'getFirms')
.and.returnValue(Observable.of(mockFirms));
});
}));
it('should show firms after getFirms observable', () => {
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
// this test passes
var rowHeaderLength = element.querySelectorAll('th').length;
expect(rowHeaderLength).toBe(8);
// this test does not, rowDataLength is 0
// selecting the rows by class so I don't get the tr in the header here
var rowDataLength = element.querySelectorAll('.animate-repeat').length;
expect(rowDataLength).toBe(10);
});
});
}
Any help is appreciated. Thanks
Related
<h2>GetAllProducts</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Genre)
</th>
<th>
#Html.DisplayNameFor(model => model.AgeId)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
#Html.DisplayFor(modelItem => item.AgeId)
</td>
<td> <button type="button" data-id="#item.Id"
class="productIdButton">AddProductToBasket</button></td>
</tr>
}
#section scripts {
<script type="text/javascript">
$("button").click(function () {
//returns all the product ids
//want to return the selected id of the button clicked
// var h = ($(this).data("id"));
var h= ($(this).attr("data-id"));
var productId = (h.Id);
var s = productId;
//alert(productId);
$.ajax({
url: "/api/BasketAPI/AddProductToBasket/",
type: "POST",
data: { id: productId },
contentType: false,
cache: false,
processData: false,
});
});
</script>
}
I am trying to pass the data-id="#item.Id" value found in the view (JQuery) to the controller and use this value to compare to the Id of a class. I am not sure to get the id value from the ajax request.
[Route("api/BasketAPI/AddProductToBasket/")]
[HttpPost]
public void AddProductToBasket(int id)
{
var returnAllProductIds = _productService.GetProductsById().Where(X=>X.Id==id).Select(x=>x.Id).FirstOrDefault();
At the moment the id from the ajax request (the id is the product id assigned to a button. Each button has a product id assigned to it) is not being passed to the controller. I want the id in the parameter of the method in the controller to be set to the id from the ajax request. At the moment this is not being set.
Please try this.
CSHTML Pages
<h2>GetAllProducts</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Genre)
</th>
<th>
#Html.DisplayNameFor(model => model.AgeId)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
#Html.DisplayFor(modelItem => item.AgeId)
</td>
<td> <button type="button" onclick="AddProductToBasket(#item.Id)" data-id="#item.Id"
class="productIdButton">AddProductToBasket</button></td>
</tr>
}
JavaScript Code
#section scripts {
<script type="text/javascript">
function AddProductToBasket(productid)
{
try
{
$.ajax({
url: "/api/BasketAPI/AddProductToBasket",
type: "POST",
data: { id: productid },
success: function(oData){
alert(oData);
},
error:function(error)
{
alert(error);
}
});
}
catch(e)
{
alert(e.message);
}
}
</script>
}
Controller Action
[Route("api/BasketAPI/AddProductToBasket/")]
[HttpPost]
public int AddProductToBasket(int id)
{
var returnProductId = _productService.GetProductsById().Where(X=>X.Id==id).Select(x=>x.Id).FirstOrDefault();
return returnProductId;
}
I created a web route that must delete a contact based on a specific id and it looks like this:
Route::delete('/api/deleteContact/{id}', 'ContactController#destroy');
Then inside the controller, I have the following:
public function destroy($id)
{
// delete a contact by id
return response()->json(Contact::whereId($id), 200);
}
Inside one of my blade template files, I call the Vue component which displays the list of contacts:
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Phone</th>
</tr>
</thead>
<tbody>
<tr v-for="contact in contacts">
<td> {{ contact.id }} </td>
<td> {{ contact.name }} </td>
<td> {{ contact.phone }} </td>
<td><button class="btn btn-secondary">Edit</button></td>
<td><button #click="deleteContact(contact.id)" class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
The delete button calls the deleteContact method and received the contact id in question.
The method looks like this:
deleteContact(id){
axios.delete('/api/deleteContact/' + id)
.then(res => {
for(var i = 0; i < this.contacts.length; i++) {
if(this.contacts[i].id == id) {
this.contacts.splice(i, 1);
}
}
})
.catch(err => console.log(err));
}
When I click to delete, the promise(then) occurs, however, after refreshing the page, I noticed that nothing was deleted and I see no errors in the console.
How can I successfully delete the contact based on the id passed in the deleteContact function ?
You have to append delete at the end of query like this:
public function destroy($id)
{
// delete a contact by id
return response()->json(Contact::where('id',$id)->delete(), 200);
}
I actually have projects and modules table. When i click button,
i want to get the data from model of that specific project.
Here is my code :
this is my table where i want to show the data of modules that represent specific project.
<table class="report">
<tr>
<th class="report-th"> Module ID </th>
<th class="report-th"> Module Name </th>
<th class="report-th"> Module Status </th>
</tr>
#if($modules->where('project_id','=',$project->id))
#foreach($modules as $module)
<tr>
<td>{{$module->id}}</td>
<td>{{$module->title}}</td>
<td>{{$module->status}}</td>
</tr>
#endforeach
#endif
</table>
below is the code in controller:
public function show()
{
$sortBy = 'id';
$sortDirection = 'ASC';
if (request('sortby') || request('sortdir')) {
$sortBy = request('sortby');
$sortDirection = request('sortdir');
}
$projects = projects::orderBy($sortBy, $sortDirection)->paginate(6);
$modules= modules::all();
return view('tms.projects', compact('projects','modules'));
}
I want to send array of id's to backend with one button from vuejs table but i get error 500.
Logic
Check the check boxes
Collect the id's
Send id's to back-end when click on button
update the view
Code
template
<table class="table table-dark table-hover table-bordered table-striped">
<thead>
<tr>
<th class="text-center" width="50">
//the button
<button class="btn btn-outline-danger" #click="withdraw(index)">Withdraw</button>
</th>
<th class="text-center" width="50">#</th>
<th class="text-center">Amount</th>
</tr>
</thead>
<tbody>
<tr v-for="(income,index) in incomes" v-bind:key="index">
<td class="text-center">
//check box input
<input v-if="income.withdraw == '0'" type="checkbox" :id="income.id" :value="income.amount" v-model="checkedNumbers">
</td>
<td class="text-center">{{index+1}}</td>
<td class="text-center">Rp. {{formatPrice(income.amount)}}</td>
</tr>
<tr>
<td colspan="2"></td>
<td>
<span>Withdraw for today, Sum: <br> Rp. {{ formatPrice(sum) }}</span>
</td>
</tr>
</tbody>
</table>
script
export default {
data() {
return {
incomes: [],
checkedNumbers: [],
}
},
computed: {
sum() {
return this.checkedNumbers.reduce(function (a, b) {
return parseInt(a) + parseInt(b);
}, 0);
}
},
methods: {
withdraw(index) {
let checkedids = this.incomes[index]
axios.post(`/api/withdrawbutton/`+checkedids).then(response => {
this.income[index].withdraw = '1'
this.$forceUpdate()
});
}
}
}
route
Route::post('withdrawbutton/{id}', 'IncomeController#withdrawbutton');
controller
public function withdrawbutton($id)
{
$dowithdraw = Income::where('id', $id)->get();
$dowithdraw->withdraw = '1';
$dowithdraw->save();
return response()->json($dowithdraw,200);
}
Any idea where is my mistake and how to fix it?
......................................................................................................................
Don't send the list as a GET parameter, send it as a POST:
let params = {}
params.ids = this.checkedNumbers
axios.post(`/api/withdrawbutton/`, params)
.then(response => {
this.income[index].withdraw = '1'
this.$forceUpdate()
});
Controller
public function withdrawbutton(Request $request)
{
$dowithdraws = Income::whereIn('id', $request->input('ids', []));
$dowithdraws->update(['withdraw' => '1']);
return response()->json($dowithdraws->get(), 200);
}
Route
Route::post('withdrawbutton/', 'IncomeController#withdrawbutton');
And I don't think you need to update anything in the front because you already have them checked (if you want to keep them checked)
I'm using Laravel 5.6 and Vuejs 2.
If I click on my checkbox and make the value true it's supposed to save a 1 in the database and if I click my checkbox and make the value false it saves a 0.
The problem I'm having is that if I click my checkbox and make it true, it doesn't save the correct value, no changes is made to the database and I don't get any errors. If I click on my checkbox and make it false, it saves the 0 correctly.
I did notice that even when my value is supposed to be true, I do get a false when I dd($category->has('active')
I'm not sure where I'm going wrong or how to fix it.
My vue file
<template>
<div class="card-body">
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Active</th>
<th scope="col">Title</th>
<th scope="col">Edit</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="(category, index) in categoriesNew" >
<td>
<label>checkbox 1</label>
<input name="active" type="checkbox" v-model="category.active" #click="checkboxToggle(category.id)">
</td>
<td>
{{ category.title }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: ['categories'],
data(){
return {
categoriesNew: this.categories
}
},
methods: {
checkboxToggle(id){
console.log(id);
axios.put('/admin/category/active/'+id, {
categories: this.categoriesNew
}).then((response) => {
//Create success flash message
})
},
},
mounted() {
console.log('Component mounted.')
}
}
</script>
my routes
Route::put('admin/products/updateAll', 'Admin\ProductsController#updateAll')->name('admin.products.updateAll');
Route::put('admin/category/active/{id}', 'Admin\CategoryController#makeActive')->name('admin.category.active');
Route::resource('admin/category', 'Admin\CategoryController');
Route::resource('admin/products', 'Admin\ProductsController');
my CategoryController#makeActive
public function makeActive(Request $request, $id)
{
$category = Category::findOrFail($id);
if($request->has('active'))
{
$category->active = 1;
}else{
$category->active = 0;
}
$category->save();
}
I hope I made sense. If there is anything that isn't clear or if you need me to provide more info, please let me know
Try changing this line
categories: this.categoriesNew
to
categories: category.active
and add a data prop at the top called category.active: ''
I've managed to get it to work. This is what I did.
vue file
<template>
<div class="card-body">
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Active</th>
<th scope="col">Title</th>
<th scope="col">Edit</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="(category, index) in categories" >
<td>
<label>checkbox 1</label>
<input type="checkbox" v-model="category.active" #click="checkboxToggle(category)">
</td>
<td>
{{ category.title }}
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: ['attributes'],
data(){
return {
categories: this.attributes,
}
},
methods: {
checkboxToggle (category) {
axios.put(`/admin/category/${category.id}/active`, {
active: !category.active
}).then((response) => {
console.log(response)
})
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
my routes
Route::put('admin/category/{category}/active', 'Admin\CategoryController#makeActive')->name('admin.category.active');
and my CategoryController#makeActive
public function makeActive(Request $request, $id)
{
$category = Category::findOrFail($id);
if(request('active') === true)
{
$category->active = 1;
}else{
$category->active = 0;
}
$category->save();
}