I'm developing my first Nova field. It's an index field that contains a button which sends an Axios request, and when a response is being returned I need to reload the index view.
For now I got this:
this.$router.go(this.$router.currentRoute);
The problem is that it refreshes the entire page (a hard-refresh, like when you press Cmd+R). I just want to reload the current route (which is the index route of a resource).
I also tried this:
this.$router.push({
name: 'index',
params: {
resourceName: this.resourceName,
},
});
But since I pushed the same route, it does nothing.
Any ideas?
Thank's, Daniel.
You can try something like this
let currentFilters = _.cloneDeep(this.$store.state[`${this.resourceName}`]['filters']);
await this.$store.commit(`${this.resourceName}/storeFilters`, {});
await this.$store.commit(`${this.resourceName}/storeFilters`, currentFilters);
This code will reset currently applied filters to empty object and then requests old filters again which leads to resource index updating. But be careful - this method makes two requests to the server.
I'm facing the same issue now while trying to implement custom popup component - but that's all I could do with implemented in Nova vuex store.
Idea of implementation was taken from https://github.com/tanmuhittin/nova-reload-resources/blob/f27da9507a97696b7aca0e9bd7e5afd3001f0891/resources/js/components/Card.vue#L21
Related
I'm not used to Vue components. My second problem is, I wanted to pass data from laravel blade, to vuejs component in the right way. Because what I did is I store it to props, then pass the props into the data property, like this:
//ticket blade
<ticket-create :menu-categories-prop="{{ json_encode($menuCategories) }}"></ticket-create>
//ticket component
export default {
props: ['menuCategoriesProp'],
created(){
this.menuCategories = this.menuCategoriesProp;
},
data() {
return {
menuCategories: [],
}
}
}
now I have menuCategoriesProp and menuCategories data, which is kinda redundant. Am I doing it wrong?
It is not a redundancy problem, it's a logic problem. You should not pass ANY variable from blade to view in my opinion. You should do something like this:
Your controller (maybe from the index method) checks if the request wants a JSON response, if not returns the view, otherwise the collection as a JSON response (go on to understand why).
When the view is loaded, VueJs loads the component and (this is how I do it) within the mounted method you make an Ajax call (maybe with axios) to your controller which will return the collection
In this way you have an asynchronous request management, that will allow you to refresh the data, and avoid to reload the page each time.
As I wrote before, I would avoid as much as possible to pass properties from blade to vue, unless they're context variables like user preferences or system settings.
Your code is ok. You can get categories over ajax. In your case, it is not recommended to use ajax.
In Sails.js, a route is set up against a controller method which can render a view. For the most part, this is straightforward, i.e. you could set up a GET /users route that points to UserController.find (which is usually set up automatically anyway).
However, say the home page of a blog renders the 10 most recent posts in the main section and a column with a list of authors and categories. The controller method has to fetch posts, authors, and categories before rendering the view and sending it back to the client. Clearly, a method like this doesn't really belong in PostController, AuthorController, or CategoryController.
What's the best thing to do in this situation? Create a controller for rendering views that rely on data from multiple models? Is there a good name for such a controller?
Thanks!
What I would do (this is purely opinion-based) is creating a PageController and create an action for each page you'd want.
For your home page example you can create a home action, get whatever you need and then render it with res.ok() (if everything is fine).
Another option would be to use Sails as a pure API and use HTTP requests (Ajax) or sockets to get your data in JSON. If you want to do so, I'd advise you to use a front end framework such as Angular, Ember, React...
By the way you could also create actions rendering HTML in your existing controllers and create a route to hit them through Ajax requests and just print them in your page. I'd prefer the 2nd solution because it takes full advantage of the Blueprint API (you don't need new controller or action whatsoever).
As Yann pointed out, this answer has to be a little opinionated. It seems that you are using the views system and not building a single page application. For the home page, I would go for an IndexController.js file with a home(req, res) action.
// api/controllers/IndexController.js
module.exports = {
home: function (req, res) {
// Retrieve all the information you need
// Take care about managing the asynchronous calls before rendering the view
return res.view('homepage');
}
};
Declare the route
// config/routes.js
module.exports.routes = {
'get /': 'IndexController.home'
}
Create the view in views/homepage.ejs.
I am using the Angular UI Router and this works well in most situations. However, I have a situation where I don't know the names of the query string parameters ahead of time.
So normally with UI router you would define a route something like this:
$stateProvider.state('test', {
url: '/test?testQueryStringParam',
templateUrl: 'Test.html',
controller: 'TestController'
});
Then in my controller I can access the testQueryStringParam using $stateParams.
However, with UI router you can't access any query string parameters not specified in the route definition.
The router that comes with the Angular framework, does allow you to do this. So I have tried using the $location service with my UI router defintion. This does sort of work.
When I want to add a query string parameter I use:
$location.search("paramName", "paramValue");
When I want to get the query string values I just use:
$location.search()
This updates the URL, but doesn't re-instantiate the controller (like $state.go($state.current, {}, {reload: true}) would). This doesn't seem like a big problem because I can just re-load the data myself. However, if you use the back button in the browser, again it changes the URL, but doesn't re-instantiate the controller.
Is there anyway
I can get this to work using just the UI Router?
Get the workaround of using $location to actually re-instantiate the controller.?
As a last resort I also tried directing updating the window.location, but this refreshes the entire page which isn't acceptable.
Thanks
You can pass non url parameters that do not appear in URL
$stateProvider.state('test', {
url: '/test?testQueryStringParam',
params: {
optParam: null,
},
templateUrl: 'Test.html',
controller: 'TestController'
});
As you can see, optParam is an optional parameter with a default value of null and will not be visible in the URL
You can access this param in your controller using $stateParams
$stateParams.optParam
Here is a helpful blog
Let me tel the scenario where I am stuck, I will try to explain simply rather than telling the actual.
1st : I am on page 1. Where few subjects are there with unique names.
2nd : I will click on one subject, which will call an struts2 action (lets call it ActionA)at back end with the unique subject name as a request parameter(Request type = GET).
3rd : Action A will only redirect to "Tutorial page".
4th : While loading it will make an AJAX call to another Struts2 action (lets call it ActionB), which will return JSON containing tutorials for that Subject.
Problem: As I am calling ActionA first and passing the subject name which is just redirecting the page to some other page. On page load I am calling another action to get the JSON. I am not able to get the request parameter value at ActionB that is the one which is returning JSON.
Note: I am using Struts2-JSON plugin thats why not need two actions, one for redirecting the page another for getting the JSON at page load.
Solution tried: I have tried to get the request parameter value that is the Subject name, putting a hidden field in the Tutorial page. But unable to get the value from inside the Angular JS controller.
Here is the example for a shared Service: http://plnkr.co/edit/P2ItVj20RYCJVjdIaXfY
But you are right if you reload the page this doesn't work. I think your scenario needs tweaking if you want to use angular or any other single page framework for that matter. One purpose of single page applications is to minimize reloads, preferable none. If your action A only returns a template where you then want to input the result of action B, I recommend looking at ngRoute or uiRouter, where you define a template (result of action A) and a controller for that view. This template than replaces a section of your page (ng-view) with the new template. If both are new to you I would recommend looking at uiRouter, it is similar but it gives you a lot more possibilities. Both provide a "resolve" function where you can load your action B before the page is rendered.
Code from plunker
angular.module("app", [])
.controller("MainController", ['SharedService', function(SharedService) {
var vm = this;
//bind to service
vm.service = SharedService;
}]);
Service
angular.module("app")
.factory("SharedService", [function() {
var service = {
id: "test"
}
return service;
}]);
I am using the following code to achieve something like domain.com/actionName1, domain.com/actionName2 and so on to reach actions that reside in home controller.
routes.MapRouteLowercase("DefaultRoutes",
"{action}",
new { controller = "Home" },
new { action = new homeActionConstraint() });
It works fine. But how do I stop user from entering domain.com/home/actionName1 etc. and still reaching the action instead of 404 or something?
You need to remove the default {controller}/{action}/{id} route that matches that URL.
(or constrain it to not match)
take out the default route, just delete it and everything will stop working the normal way or you can map the default root to the 404 page you desire, however that is a little strange even for SO