I have created a route, for search which is searching users, and the application.hbs is having the search form, below are the segments of my code.
ROUTER router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
export default Router.map(function() {
this.resource('search', {path: '/search/:citySef/:group'});
});
Route application.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return Ember.RSVP.hash({
groups: this.store.find('group'),
cities: this.store.find('city', {type: 'filled'})
});
},
setupController: function(controller, models) {
controller.setProperties(models);
}
});
Route search.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params){
return Ember.RSVP.hash({
users: this.store.find('user', {citySef: params.citySef, group: params.group})
});
},
setupController: function(controller, models) {
controller.setProperties(models);
}
});
Controller application.js
import Ember from 'ember';
export default Ember.Controller.extend({
isProcessing: false,
selectedCity: null,
selectedGroup: null,
actions: {
submitSearch: function () {
this.setProperties({
isProcessing: true
});
var citySef = this.get("selectedCity");
var group = this.get("selectedGroup");
console.log(citySef, group);
this.transitionToRoute('search', {citySef:citySef, group:group});
}
}
});
Controller search.js
import Ember from 'ember';
export default Ember.Controller.extend({
});
So basically I am creating a url like localhost:4200/search/City/Group to search users within a city with specific group.
When I press the search button, i can see that the URL is changed in the address bar from localhost:4200 to localhost:4200/search/City/Group but it dont send request to server to get data from REST, but when i do refresh the page, then it loads the data.
Edit
I have included pretty much everything apart from templates.
Edit 2015-04-22
I have uploaded the package (without bower and npm packages) to https://drive.google.com/file/d/0B5slzmNBINvNMHNjcXdqNWlCeUk/view?usp=sharing
I guess the problem in your case is model is not getting set properly first time.
Firstly you don't have to call setupController function explicitly when you have model function in your route, since model hook handles all these settings.
But if you want then the convention should be like -
setupController:function(controller,models){
controller.set('content',models);
}
try using setup controller function in above pattern.
As per Neha suggested, it was related to setupController
setupController: function (controller, models) {
if (models.citySef) {
controller.set('model', this.store.find('user', {citySef: models.citySef, group: models.group}));
} else {
controller.set('content', models);
}
}
So when page loads it goes to else condition, and if i transitiontoroute it goes in if conditon. I think this can be cleaned but so far it is working for me.
Related
Hitting a link from a website without visiting the Homepage is not setting the values in the store.
I have made axios calls in nuxtServerInit action and have set the data in mutations. I am able to access this data everywhere in the project now but if I load a particular page from the website then the data is not shown until refreshed.
Following is store/index.js file
/* eslint-disable */
import Vuex from 'vuex'
import axios from 'axios'
const createStore = () => {
return new Vuex.Store({
state: {
organisation: Object,
},
mutations: {
setOrganisation(state, organisation){
state.organisation = organisation
},
},
actions: {
nuxtServerInit({ commit }, context){
axios.get(api-link-to-fetch-data-from-backend))
.then(res => {
commit("setOrganisation", res.data[0])
})
.catch(e => context.error(e));
}
},
getters: {
getOrganisation(state){
return state.organisation;
}
}
})
}
This data needs to be used in the navigation bar. So it is being fetched from the store in layout/default.vue in the created method like this,
created() {
this.organisation = this.$store.getters.getOrganisation;
}
As nuxtServerInit is the first function that is called in the nuxt lifecycle why is the data not being stored when any link from the website is accessed directly?
Example here:
Post
This information about the recent videos gets set after refreshing the page.
I have a laravel app and a Vue instance attached to the body (or a div, just inside the body).
const app = new Vue({
el: '#app'
});
I think it makes sense to use the Vue instance for stuff relating to the layout (eg header, nav, footer logic).
Now I have a form that is visible on a specific route (e.g. example.com/thing/create). I want to add some logic to it, e.g. hiding a field based on selected option in the form. It is logic meant for just this form (not to be reused). I prefer not to put all the logic inline with the form but put it in the app.js. I could put it in the Vue instance bound to the body but that sounds odd as it only applies to the form that is much deeper into the dom.
I want to leave the markup of the form in the blade template (that inherits the layout).
I tried creating a component but am not sure how to bind this inside the main Vue instance. What is the best way to handle things for this form, put it in the app.js and have it somewhat structured, putting the variables somewhat into scope. Or is it really necessary to remove the main Vue instance bound to the full layout code?
What I tried was something like this, but it does not work (attaching it to the <form id="object-form"> seems to fail:
var ObjectForm = {
template: function() { return '#object-form'},
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
}
};
Things do work if I remove the #app Vue instance or when I put everything directly in the app Vue instance. But that seems messy, if I have similar variables for another form they should be seperated somewhat.
I would appreciate some advice regarding the structure (differentiate page layout and page specific forms) and if possible some example to put the form logic inside the main app.js.
I hope this helps kind of break things down for you and helps you understand Vue templating.
It is best to take advantage of Vue's components. For you it would look something like this. Some of this code depends on your file structure, but you should be able to understand it.
In your app.js file (or your main js file)
Vue.component('myform',require('./components/MyForm.vue'));
const app = new Vue({
el: "#app"
});
Then create the MyForm.vue file
<template>
<form>
Put Your Form Markup Here
</form>
</template>
<script>
// Here is where you would handle the form scripts.
// Use methods, props, data to help set up your component
module.exports = {
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
},
methods: {
// add methods for dynamically changing form values
}
}
</script>
Then you will be able to just call in your blade file.
<myform></myform>
I found out how to do it. The trick was to use an inline template. Surround the form in the view with:
<object-form inline-template>
<form>...</form>
</object-form>
Where object-form is the name of the component. In the ObjectForm code above I remove the template, like this:
var ObjectForm = {
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
}
};
I attach the component within the root vue app like this:
const app = new Vue({
el: 'body',
components: {
'object-form': ObjectForm
}
});
This way I can use the form as it was generated from the controller and view and I can separate it from the root (attached to body) methods and properties.
To organize it even better I can probably store the ObjectForm in a seperate .vue file the way #Tayler Foster suggested.
How do you handle Angular 2 forms in unidirectional data flow? Especially with validation between several parent/child components?
I am using ngrx/store and model driven forms with form builder.. Is it possible to do something similar like form reducer in React and make it as a part of Store?
Do you have some articles about it?
I have created a library called ngrx-forms that does exactly what you want. You can get it on npm via:
npm install ngrx-forms --save
I recommend checking out the full README on the github page, but below you can find some examples of what you need to do to get the library up and running once installed.
Import the module:
import { StoreModule } from '#ngrx/store';
import { NgrxFormsModule } from 'ngrx-forms';
import { reducers } from './reducer';
#NgModule({
declarations: [
AppComponent,
],
imports: [
NgrxFormsModule,
StoreModule.forRoot(reducers),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Add a group state somewhere in your state tree via createFormGroupState and call the formGroupReducer inside your reducer:
import { Action } from '#ngrx/store';
import { FormGroupState, createFormGroupState, formGroupReducer } from 'ngrx-forms';
export interface MyFormValue {
someTextInput: string;
someCheckbox: boolean;
nested: {
someNumber: number;
};
}
const FORM_ID = 'some globally unique string';
const initialFormState = createFormGroupState<MyFormValue>(FORM_ID, {
someTextInput: '',
someCheckbox: false,
nested: {
someNumber: 0,
},
});
export interface AppState {
someOtherField: string;
myForm: FormGroupState<MyFormValue>;
}
const initialState: AppState = {
someOtherField: '',
myForm: initialFormState,
};
export function appReducer(state = initialState, action: Action): AppState {
const myForm = formGroupReducer(state.myForm, action);
if (myForm !== state.myForm) {
state = { ...state, myForm };
}
switch (action.type) {
case 'some action type':
// modify state
return state;
default: {
return state;
}
}
}
Expose the form state inside your component:
import { Component } from '#angular/core';
import { Store } from '#ngrx/store';
import { FormGroupState } from 'ngrx-forms';
import { Observable } from 'rxjs/Observable';
import { MyFormValue } from './reducer';
#Component({
selector: 'my-component',
templateUrl: './my-component.html',
})
export class MyComponent {
formState$: Observable<FormGroupState<MyFormValue>>;
constructor(private store: Store<AppState>) {
this.formState$ = store.select(s => s.myForm);
}
}
Set the control states in your template:
<form novalidate [ngrxFormState]="(formState$ | async)">
<input type="text"
[ngrxFormControlState]="(formState$ | async).controls.someTextInput">
<input type="checkbox"
[ngrxFormControlState]="(formState$ | async).controls.someCheckbox">
<input type="number"
[ngrxFormControlState]="(formState$ | async).controls.nested.controls.someNumber">
</form>
This is a fairly old question, but I couldn't find a great solution in my own quest for working with ngrx + reactive forms in Angular. As a result, I'll post my research here with hope that it may help someone else. My solution can be broken down into two parts, and I pray you (oh weathered soul) find it applicable to your problem:
1) Monitor the form element/s (for example, "keyup" event for a typical text input), and update the State from that event. This strategy comes straight out of the book search component in the ngrx example app. We can now successfully populate the State as our form changes. Awesome! 50% done!
2) The angular reactive forms guide demonstrates creating the form group in the constructor. I have seen some other people do it inside ngOnInit, but this is too late in the lifecycle for our needs (I tried, I failed). Now that we have our form group established, setup ngOnChanges to capture any changes pushed from the state, and then update the form group using patchValue. For example:
ngOnChanges(changes: SimpleChanges) {
if (changes.valueICareAbout1) {
this.myForm.patchValue({
valueICareAbout1: changes.valueICareAbout1.currentValue
});
}
if (changes.valueICareAbout2) {
this.myForm.patchValue({
valueICareAbout2: changes.valueICareAbout2.currentValue
});
}
}
In the applications I built with Angular 2, the following guideline seemed to work well:
Parent components pass data down to children via data binding. Child components request data changes by emitting output events to parent components. It is the parent components responsibility to act accordingly.
In a hierarchical component structure, data changes are handled by the lowest component that depends on the data. If there's another component higher up or a sibling that depends on the same data item, pass changes up by emitting events and leave the handling to a higher component.
This scheme works well because, for any data that is relevant to more than one component, there is a single component responsible for performing changes. Changes bubble down automatically. Components are reusable, and changes in the component tree can be easily adapted.
With regard to validation, any component in the ladder between the lowest component emitting a data change request up to the highest component that finally handles the change, any component can effectively cancel the change by not passing it higher up. In most applications, I'd opt for validating data changes at the origin of the change though.
Naturally, child components can still have internal state and need not communicate changes - unless changes are relevant to the parent component.
Form data is inherently a very local state, especially for Angular since ngModel binds to local component variables. The top devs that I know recommend keeping the data for the form localized to that component (ie just use ngModel with local variables). This is because un-submitted form data is almost never shared by various components across your whole application. When the user submits the form then you can dispatch an action with a payload containing the form data to a parent component, to the store, or even to an ngrx/effect to be posted to a server.
I am building a magnetic poetry game in Meteor
http://test-magnets.meteor.com/
The homepage allows everyone online to play on the same "fridge" I want to have an option that allows you to create your own fridge without the public disturbing it.
I used Iron Router to generate a url based on the userID. The magnets have a fridgeId. The fridgeId for the home page is 1 and when a user goes into the url based on their userId, the magnets fridgeId gets updated to be the same as the userId.
Currently when you move a magnet in the homepage it also makes the change in the user's private fridge. Is it possible to use publish and subscribe or the iron router just to update the database for the magnets depending on my generated fridgeId? Any suggestions are greatly appreciated. Thanks
-John
Here is some code I have now.
iron router
Router.map(function() {
this.route('home', {
path: '/'
});
var user = Meteor.userId();
this.route('private', {
path: '/' + user
});
});
magnets collection
if (Meteor.isServer) {
Meteor.publish('magnets', function(){
return Magnets.find();
});
}
if (Meteor.isClient) {
Meteor.subscribe('magnets', function(){
return Magnets.find();
});
}
some helpers that set the fridgeId
Template.home.events = {
'click #new-board': function() {
var user = Meteor.userId();
var magnet = Magnets.findOne();
Magnets.update({_id: magnet._id}, {$set: {fridgeId: user}});
}
};
Template.private.events = {
'click #group-fridge': function() {
var magnet = Magnets.findOne();
Magnets.update({_id: magnet._id}, {$set: {fridgeId: 1}});
}
};
I'm new to Ember JS and I am trying to figure out how to create Ember.Select which would allow to create new job for user.
This is part of the code from my form.handlebars:
{{view Ember.Select viewName="job-user"
contentBinding="users"
optionLabelPath="content.name"
optionValuePath="content.id"
}}
I am inside JobsNewController:
JP.JobsNewController = Ember.ObjectController.extend({
needs: ['users'],
users: [],
usersBinding: "controllers.users"
});
This is how my UsersController looks like:
JP.UsersController = Ember.ArrayController.extend();
It's working when I go to newJob screen from screen where I have UserController populated, but when I go directly to jobs/new it fails to populate select with data. How can I force Ember to load data for this select?
EDIT:
I had to setup routes correctly:
JP.JobsNewRoute = Ember.Route.extend( JP.JobsFormable, {
model: function() {
return JP.Job.createRecord();
},
setupController:function(controller,model) {
this._super(controller,model);
controller.set('usersForSelect', JP.User.find());
}
});
And I have also modified form:
{{view Ember.Select viewName="job-user"
contentBinding="usersForSelect"
optionLabelPath="content.name"
optionValuePath="content.id"
}}
Thanks #mavilein for hint
When you access the JobsNewRoute from the URL, the UsersController is not populated. So binding users in JobsNewController to UsersController content would be useless since UsersController is empty and was not populated.
You can solve this in two ways, both are in the JobsNewRoute.
First way, update your JobsNewRoute to fill the UsersController:
JP.JobsNewRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controllerFor('users').set('content', JP.User.find());
}
});
Another way would be to remove the binding between JobsNewController.users and UsersController, and simply fill JobsNewController.users in the JobsNewRoute:
JP.JobsNewController = Ember.ObjectController.extend({
users: []
});
JP.JobsNewRoute = Ember.Route.extend({
setupController: function(controller, model) {
controller.set('users', JP.User.find());
}
});