I am not sure if I am confused, is it true that I should leave the job of getting data from database for controller and processing the data for vue? Or is this the best practice or something?
Here I am trying to get the subcat from my subcategories table, not error on devtool but subcats is not being set. Please help or feel free to suggest a better practice. Thanks!
Item-sorting-list.vue
<template>
<div>
<div v-show="isActive">
<li v-for="subcat in subcats" class="list-group-item">
<a name="" href="">{{subcategory.name}}</a>
</li>
</div>
</div>
</template>
<script>
export default {
props:[
],
data(){
return {
subcats:[]
}
},
mounted() {
this.getAllSubcat()
},
methods: {
getAllSubcat(){
var vm = this;
vm.$http.get('/getSubcat').then((response)=>{
vm.subcats = response.data.data.subcat.data;
});
}
}
}
</script>
SubcategoryController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Subcategory;
class SubcategoryController extends Controller
{
public function getSubcat()
{
$subcat = Subcategory::Orderby('name')->get();
$response = [
'data' => [
'subcat' => $subcat
]
];
return response()->json($response);
}
}
web.php
Route::get('/getSubcat', 'SubcategoryController#getSubcat');
Thanks for #saurabh that I double check and response.data.data.subcat should be the correct calling. paginate does read the data differently.
Related
When running helper brings values are stored in the variable verCandidatos.postulados.
Once I get me the information I need to get a document that is linked (using the function ng-init="candidato = la postulado.candidato()) wich runs on the helper from file: collection.js.
Sometimes the html shows the properties: {{candidato.nombre}}, {{candidato.apellidos}} and {{candidato.sexo}} correctly, and sometimes appear empty, why?
Is very strange, like a bug or something. How is possible that behavior?
The information is being obtained, because the ng-repeat works and shows elements.
Below is the publishComposite(), collection.js, html and js client
html client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.html
<div ng-repeat="postulado in verCandidatos.postulados">
<div ng-init="candidato = postulado.candidato();">
{{candidato.nombre}}
{{candidato.apellidos}}
{{candidato.sexo}}
</div>
</div>
js in client
my-app/imports/ui/components/vacantes/verCandidatos/ verCandidatos.js
imports ...
class VerCandidatos {
constructor($scope, $reactive, $stateParams) {
'ngInject';
$reactive(this).attach($scope);
this.vacanteId = $stateParams.vacanteId;
this.subscribe('vacantes.candidatosOseleccionados', ()=> [{vacanteId: this.vacanteId}, {estado: 1}]);
this.helpers({
postulados (){
return Postulaciones.find();
}
});
}
}
collection.js
my-app/imports/api/postulaciones/ collection.js
imports...
export const Postulaciones = new Mongo.Collection('postulaciones');
Postulaciones.deny({...});
Postulaciones.helpers({
candidato(){
return Candidatos.findOne({_id: this.candidatoId});
}
});
publish.js:
my-app/imports/api/vacantes/server/ publish.js
imports...
if (Meteor.isServer) {
Meteor.publishComposite('vacantes.candidatosOseleccionados', function (vacanteId, estado) {
const selector = {$and: [estado, vacanteId]};
return {
find: function () {
return Postulaciones.find(selector);
},
children: [
{
find: function (postulacion) {
return Candidatos.find({_id: postulacion.candidatoId}, {
fields: {
nombre: 1,
apellidos: 1,
sexo: 1,
}
});
}
}
]
};
});
}
Any ideas?
- Thanks,
The ISSUE was in html
The solution was deteted ng-init and call directly the helpers inside collection.js, the other files (js in client, collection.js, publish.js) aren't modify.
The html file is as follows:
<div ng-repeat="postulado in verCandidatos.postulados">
{{postulado.candidato().nombre}}
{{postulado.candidato().apellidos}}
{{postulado.candidato().sexo}}
</div>
Thanks for read.
And I hope you will be useful.
I am following the Meteor - Angular2 tutorial and things work fine.
The only point not working is the automatic binding with Angular2 UI for the 'details view'. For instance, if I navigate to the details view of Party1 the data of Party1 is correctly loaded and made visible on the Angular2 'details view'. If, afterwards, the data of Party1 is changed (e.g. via Mongo shell) such change is sent to the browser (via WebSockets) where 'details view' is displayed, but the new data is not shown on the view.
Here is the code of the PartyDetailsComponent class.
export class PartyDetailsComponent extends MeteorComponent implements OnInit, CanActivate {
partyId: string;
party: Party;
constructor(private route: ActivatedRoute, private ngZone: NgZone) {
super();
}
ngOnInit() {
this.route.params
.map(params => params['partyId'])
.subscribe(partyId => {
this.partyId = partyId;
this.subscribe('party', this.partyId, () => {
this.party = Parties.findOne(this.partyId);
}, true);
});
}
saveParty() {
Parties.update(this.party._id, {
$set: {
name: this.party.name,
description: this.party.description,
location: this.party.location
}
});
}
canActivate() {
const party = Parties.findOne(this.partyId);
console.log(party);
return (party && party.owner == Meteor.userId());
}
}
Here is the template of of PartyDetailsComponent
<form *ngIf="party" (submit)="saveParty()">
<label>Name</label>
<input type="text" [(ngModel)]="party.name" name="name">
<label>Description</label>
<input type="text" [(ngModel)]="party.description" name="description">
<label>Location</label>
<input type="text" [(ngModel)]="party.location" name="location">
<button type="submit">Save</button>
<a [routerLink]="['/']">Cancel</a>
</form>
Thanks in advance for any help
I actually found the answer to my questions just reading more of the Tutorial.
I can get automatic update ofthe UI once the underlying Mongo doc changes just adding Meteo autorun() method appropriately in the subscription code.
Here is the code that works
ngOnInit() {
this.route.params
.map(params => params['partyId'])
.subscribe(partyId => {
this.partyId = partyId;
this.subscribe('party', this.partyId, () => {
this.autorun(() => {
this.party = Parties.findOne(this.partyId);
}, true);
}, true);
});
}
What is not totally clear to me is why if you use directly the Meteo Mongo cursors (e.g. via *ngFor in the template) autorun is not needed.
I'm having some trouble displaying my data in the browser. To explain my problem I'm using some dummy code. I have some nested objects that are causing my problem. Here I'll display one nested object to showcase my problem.
First of all, I only make http calls for the Car-object. So saveCar acts like updating the car as well, depending on what the user does in the app. All the methods in the service works as they should.
So my service looks something like this:
#Injectable()
export class Service {
constructor(private http: Http) { }
saveCar(car: Car) {
return this.http.post ....
}
getCars(){
return this.http.get...
}
getById(id: string) {
return this.http.get...
}
}
Then I have a Car-class, where the nested object "Brand" comes in to play, Brand then has it's own class, but I'll leave it out.
export class Car {
private brands: Array<Brand>;
constructor(public id: string, public name: string) {
this.brands = new Array<Brand>();
}
public getBrands(): Array<Brand> {
return this.brands;
}
public addBrand(value: Brand): void {
this.brands.push(value);
}
//some other methods.
}
Then I have a list-component that lists all cars, this works as it should!
#Component({
selector: 'car-list',
template: `
<h1>Add Car</h1>
<form (submit)="saveCar()">
<input required [(ngModel)]="name" placeholder="Add car">
</form>
<br>
<table>
<tr *ngFor="let car of cars" >
<td>{{car.name}}</td>
<td><button (click)="goToDetail(car)">Detail</button></td>
</tr>
</table>
`,
})
export class ListComponent implements OnActivate {
id: string
name: string;
cars: Array<Car>
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(): void {
this._service.getCars()
.subscribe(cars => this.cars = cars);
}
saveCar() {
let car = new Car(this.id, this.name)
this._service.saveCar(Car)
.subscribe(car => this.cars.push(car));
this._service.getCars()//
.subscribe(cars => this.cars = cars);
}
goToDetail(car:Car) {
this._router.navigate(['/cardetail', car.id]);
}
}
The problem I have is in the detail-component, where the user gets navigated after clicking a specific car. The routing and retrieving the Car from the db works as it should. That I know, because if I remove all the template except <h1>Car: {{car?.name}}</h1> the name gets printed out fine with the elvis operator.
But my detail-component looks something like this:
#Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
`,
})
export class DetailComponent implements OnActivate {
#Input() car: Car;
constructor(public _service: Service, public _router: Router) { }
routerOnActivate(curr: RouteSegment): void {
let id = curr.getParam('id');
this._service.getById(id)
.subscribe(car => {
this.car = car;
});
}
addBrand() {
this.car.getBrands().push(new Brand());
}
//some other methods
}
So in my detail component I call all methods like: car.someMethod() and further on the nested Brand object like: brand.someMethod() in the template. So the error comes at the call of the method e.g in the template 'cannot get getBrands of undefined' I've tried putting the elvis operator like this: car?.getBrands() It doesn't work. I've tried to wrap the whole thing in a div, both with elvis operator and a <div *ngIf = "car"></div>, doesn't work. Even tried with <template *ngIf="car"></template>, well that doesn't work either....
Edit: my mess-up, wrapping like below, it does "kind of" work, meaning, it gives a new error....
Template:
#Component({
selector: 'car-detail',
template: `
<h1>Car: {{car?.name}}</h1>
<hr>
<button (click)="addBrand()">Add Brand</button>
<div *ngIf="car">
<div *ngFor="let brand of car.getBrands(); let i=index">
<h2>Brand {{i+1}}</h2>
</div>
</div>
You mention <h1>Car: {{car?.name}}</h1> with ? but the full code example has <td>{{car.name}}</td> without ? which will cause an error.
<div *ngFor="let brand of car.getBrands(); let i=index">
also needs a ? to avoid errors when Angular tries to render the view and car is not yet set
<div *ngFor="let brand of car?.getBrands(); let i=index">
I'm having trouble getting menu items connected to an event handler. Here's a mock of the UI showing state changes over time. It's a dropdown menu (via Bootstrap), with the root menu item showing the current selection:
[ANN]<click ... [ANN] ... [BOB]<click ... [BOB]
[Ann] [Ann]
[Bob]<click + ajax [Bob]
[Cal] [Cal]
The end goal is to change the page content asynchronously based on the user's selection. Clicking on Bob should trigger the handleClick, but it's not.
As a side note, I'm not terribly happy with the way componentDidMount calls this.handleClick();, but it works for now as a way to get initial menu content from the server.
/** #jsx React.DOM */
var CurrentSelection = React.createClass({
componentDidMount: function() {
this.handleClick();
},
handleClick: function(event) {
alert('clicked');
// Ajax details ommitted since we never get here via onClick
},
getInitialState: function() {
return {title: "Loading items...", items: []};
},
render: function() {
var itemNodes = this.state.items.map(function (item) {
return <li key={item}><a href='#' onClick={this.handleClick}>{item}</a></li>;
});
return <ul className='nav'>
<li className='dropdown'>
<a href='#' className='dropdown-toggle' data-toggle='dropdown'>{this.state.title}</a>
<ul className='dropdown-menu'>{itemNodes}</ul>
</li>
</ul>;
}
});
$(document).ready(function() {
React.renderComponent(
CurrentSelection(),
document.getElementById('item-selection')
);
});
I'm almost positive that my hazy understanding of javascript scoping is to blame, but everything I've tried so far has failed (including trying to pass the handler down through props).
The problem is that you're creating the item nodes using an anonymous function, and inside that this means the window. The fix is to add .bind(this) to the anonymous function.
var itemNodes = this.state.items.map(function (item) {
return <li key={item}><a href='#' onClick={this.handleClick}>{item}</a></li>;
}.bind(this));
Or create a copy of this and use that instead:
var _this = this, itemNodes = this.state.items.map(function (item) {
return <li key={item}><a href='#' onClick={_this.handleClick}>{item}</a></li>;
})
As I can understand the specification of the task for "Anna", "Bob", "Cal, the solution can be the following (based on a react component and ES6):
Basic live demo is here
import React, { Component } from "react"
export default class CurrentSelection extends Component {
constructor() {
super()
this.state = {
index: 0
}
this.list = ["Anna", "Bob", "Cal"]
}
listLi = list => {
return list.map((item, index) => (
<li key={index}>
<a
name={item}
href="#"
onClick={e => this.onEvent(e, index)}
>
{item}
</a>
</li>
))
}
onEvent = (e, index) => {
console.info("CurrentSelection->onEvent()", { [e.target.name]: index })
this.setState({ index })
}
getCurrentSelection = () => {
const { index } = this.state
return this.list[index]
}
render() {
return (
<div>
<ul>{this.listLi(this.list)}</ul>
<div>{this.getCurrentSelection()}</div>
</div>
)
}
}
I'm using jeditable plugin for JavaScript and I want to implement it in my Symfony2 project. I want to edit a name with the plugin and that name to be edited in the database, too, not the change to be gone when I refresh the page, but in my case, it's gone. :(
I'm almost sure that the controller shouldn't be in that way and the problem is from it, but how exactly to write it? Here it is:
public function editCategoryAction(Request $request, $id)
{
$category = $this->repository->find($id);
$form = $this->createForm(new CategoryType(), $category);
if ($request->isMethod('POST')) {
$form->bind($request);
if ($form->isValid()) {
$this->em->persist($category);
$this->em->flush();
return $this->redirect($this->generateUrl('categories'));
}
}
return $this->render(
'AcmeBudgetTrackerBundle:Categories:categories.html.twig', array(
'form' => $form->createView()));
}
This is my template:
<a href="{{ path('edit_category', { 'id': cat.id}) }}">
<strong class="edit">
{{ cat.name }}
</strong>
</a>
<script>
var token = "{{form._token.vars.value}}";
var path = "{{ path('edit_category', { 'id': cat.id}) }}";
</script>
And this is in the .js file:
(function(){
$('.edit').editable(function (value, settings) {
var data = {};
data[this.id] = value;
data["_token"] = token;
console.log(path);
console.log(data);
$.post(path, data);
return(value);
}, {
indicator:'Saving...'
});
}) ();
The output in the console looks fine:
/BudgetTracker/web/app_dev.php/edit_category/52
Object {: "Edu", _token: "9d29860b59ccafbc265ea12346c91fa7e378cc97"}
but the problem is that nothing is posted to the database and when I hit refresh the change I made is gone.
Can you please help me to solve this? Thanks in advance! :)
I think you don't need to use the form component here, you only want to handle a string. So I'll explain a way to do.
JavaScript:
$('.edit').editable(path);
Controller:
public function editCategoryAction(Category $category)
{
//check if exists/valid
//get the text sent from jeditable
$name = $this->request->get('value');
$category->setName($name);
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
//return the name value to jeditable so it can display it
return new Response($name);
}
Twig:
<strong class="edit">{{ cat.name }}</strong>
<script>
var path = "{{ path('edit_category', { 'id': cat.id}) }}";
</script>
jEditable sends edited text named as 'value', so you can get it in the controller. In your controller, you implicitly use paramconverter to get the category from the id in the URL. And that should be OK now.
Note that you can use FORJsRoutingBundle, if you want to avoid mixing twig with javascript in order to access path.