Currently I have a form called a "form A", I've created a number of views for this form, an edit, create and list. I want to be able to create a form called "form B", that will pull through "form A's ID" as a parent ID. To enable me to have a list of all form B under a "form A" (essential a one to many relationship). So at the moment under my list for "form A" I have this link for each item:
{{#link-to 'form-a.form-b.listing' form-a.id}} <!--Link to a controller -->
<span class="btn btn-primary"> form b </span>
{{/link-to}}
Here is also my router
this.route('form-a', function() {
this.route('new');
this.route('listing');
this.route('edit', {path: '/edit/:form-a_id' });
this.route('form-b', function() {
this.route('listing', {path: '/listing/:form-a_id'});
this.route('new');
});
});
So I'm trying to pull through the Id of form-a for the listing. However I'm kind of stuck here as I'm unsure how what to do next and how to correctly pull through "form a" Id in the listing controller and the use it as a parent ID for each "form B". Is there a better way to have nested forms with one too many relationships or am I going about it in the best way?
I hope someone can help as this issue as I have hit the coding wall. If you need any clarifications please ask as I know I'm usually terrible at describing my issues.
This post applies to Ember 2.x.x and was written as of 2.15.
I think what will help you out a lot is paramsFor().
It's hard to say what the "right" routing structure because your UI will dictate things somewhat, and I'm not sure how much exact URLs matter.
Here's how I would set up the routes, assuming there will be multiple form a's in time.
this.route('form-as', function() {
this.route('form-a', {path: '/:form-a_id'}, function() {
this.route('new');
this.route('listing');
this.route('edit');
this.route('form-b', function() {
this.route('listing', {path: '/listing'});
this.route('new');
});
});
});
In the code above, new, listing, and edit under form a will have access to the form a id via the params in the model hook of the routes:
model(params) {
console.log(params['form-a_id'])
// using the [] accessor since dashes don't work for normal dictionary nav
}
In the form b segment, listing and new can get access to the form-a parameters like this:
model() {
console.log(this.paramsFor('form-as.form-a'))
}
Watch out for those dasherized ids and model names. They are a likely source of bugs and I'm not 100% sure I got them right here. I avoid them.
For more about paramsFor(), see Reusing Route Context in the Guides and Dynamic Segments
Related
Here is what I am doing :
I have a form set component that fetch data through ajax to populate the form set.
The user may modify those datas from the form and submit.
Problem : This work well. However, I noticed that if i navigate to another page and then hit the browser "go back one page" button, the form is there (the DOM in the template) but empty.
There is no data bound in v-model input fields anymore...
Most posts about this behavior are connected to vue-router, that I do not use.
I think it might have to deal with lifecycle hooks...
Actually, on my component, I fetch the data when "mounted".
But, if so, which lifecycle ?
I also tried "keep-alive" without success.
I put some verbose log on my component to try to catch the lifecycle hook when browser going back and none of them printed...
beforeCreate: function() {
console.log('---- BEFORE CREATE ----> ')
},
created: function() {
console.log('---- CREATED ----> ')
this.getModelObjects();
},
beforeMount: function() {
console.log('---- BEFORE MOUNT ----> ')
},
mounted: function() {
console.log('---- MOUNTED ---->')
this.getModelObjects();
},
beforeUpdate: function() {
console.log('---- BEFORE update ----> ')
},
updated: function() {
console.log('---- UPDATED ----> ')
},
beforeDestroy: function() {
console.log('---- BEFORE DESTROY ----> ')
},
destroyed: function() {
console.log('---- DESTROYED ----> ')
},
Any idea?
OK, I solved this problem in the most easiest way possible!
Actually, using localStorage (https://fr.vuejs.org/v2/cookbook/client-side-storage.html), would not solve the problem.
In anyway, it needs to be tied to a lifecycle hook in order to be triggered. Therefore, as I already sync those datas on a backend database with Axios, this would add redundant complexity and end up with the same problem.
I also noticed that only v-model fields where concerned. {{ var }} were not. So, I ended up thinking this was really related to forms.
Instead, I used autocomplete="on" in my forms.
<form method="post" autocomplete="on">
.....
</form>
But, in fact, autocomplete is "on" by default :
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
The persistence feature is enabled by default. Setting the value of
the autocomplete attribute to off disables this feature.
I don't remember why, but I used autocomplete="off" in my forms :-( ...
This might be why I don't see much posts about it...
Now, if a user click to a link on the page, and then navigate backward with the "go one page back" button, v-model binded fields are there.
I have 2 tables in database Industry and Category. They are joined using IndustryId as primary key and Foreign key in tables.Now I want to show Industry as my main menu item and Related categories as my sub menu items of respective industries. I am using asp net mvc enity framework as my coding architecture with visual studio 2017.This is my first application on this architecture I want a brief explanation including models views and controllers step by step.I have done this binding earlier on asp net web forms without mvc. But entity frameworks is seems to be totally different from previous versions.
Edit based on user comment, he want to bind the data on load, making nested list, I will leave my old answer as it might help someone else, I will add the new answer as well,
my suggestion is you pass List of Industries as a ViewBag, since there is foriegn key in categories which is industryid relating to industry table, ef will detect that relationship and represent it in your Industry Model as virtual Collection<Category> Categories, this represents all categories associated with this industry.
what you can do is pass it then using razor syntax do something like this in your view
in your controller you pass it as viewbag
ViewBag.Industries = dbContext.Industries.Include(x => x.Categories).ToList();
then in your view
<!-- init your list -->
<ul>
<!-- loop through your viewbag -->
foreach (var x in (List<Industry>) ViewBag.Industries)
{
<li> x.IndustryName
<!-- init your sub menu -->
<ul>
<!-- loop through your categories of this industry x -->
foreach(var c in x.Categories)
{
<li> c.CategoryName </li>
}
</ul>
</li>
}
<!-- loop end, close your list -->
</ul>
For People looking to update their menu content dynamically according to another menu value, read below:
What I do to solve such thing is, first create action which accepts industry id and return List or categories, I use ajax to call this action whenever my industry id list change in the front end (change event listener), then get the return as list of object, bind the data to my sub menu using jquery.
something like
public ActionResult GetCategories(int IndustryID)
{
// this simple select query, retrieves all categories that have industry id provided
var categories = dbContext.Categories.Where(c => c.IndustryId == IndustryID).ToList();
return Json(categories);
}
ajax code
// industryId is the id of industry in your view, apply change event listener
$('#industryId').change(function () {
// ajax call, get data
$.ajax({
type: "POST",
url: '#Url.Action("GetCategories", "controllerhere")',
data: { IndustryID: this.value},
dataType: "json"
}).done(function(data){
// Data recieved, get categories list, empty it, bind the new data
var ddl = $("#categoriesList");
ddl.empty();
ddl.append($('<option>', {value: 0,text: 'Select'})); //Newly added
// categoryID and CategoryName are properties in your category, these Names I assumed, they might change depending on your Model
$.each(data, function () {
ddl.append($('<option></option>').attr("value", this.CategoryID).text(this.CategoryName));
});
});
});
I hope this answered your question, I am not sure what did you mean when you said entity framework is different, you can ask me more specific questions maybe i can help
Say I wrote a blog app in Sails.js.
On every page in this app, there is a sidebar widget called "Recent Posts", where it lists the titles of the 5 most recent posts and clicking on them takes you to the post in question.
Because this sidebar widget is present on every page, it should be in layout.ejs. But, here we have a conflict - dynamic content is only supposed to be pulled from the database in the controller action for rendering a specific view.
This dynamic content isn't for a specific view, it's for the whole site (via layout.ejs).
By the conventions that I understand, I'd have to get that dynamic content data for the sidebar widget in every controller action that renders a view (otherwise I would get an undefined error when I attempt to call that local in my layout.ejs file).
Things I've tried / considered:
Load that dynamic content in every controller action that renders a view (this solution is very bad) and calling that dynamic content in layout.ejs as if it were a local for the specific view. This works fine, but goes against D.R.Y. principles and quite frankly is a pain in the ass to have to run the same query to the database in every controller action.
As per another similar stackoverflow question, create a new config (E.G. config/globals.js), load my dynamic content from my database into that config file as a variable, and then calling sails.config.globals.[variable_name] in my layout.ejs file. This also worked, since apparently config variables are available everywhere in the application -- but it 's a hacky solution that I'm not a fan of (the content I'm loading is simply the titles and slugs of 5 recent posts, not a "global config option", as the solution implies).
Run the query to get the dynamic content inside the .EJS file directly between some <% %> tags. I'm not sure if this would work, but even if it did, it goes against the separation of concerns MVC principle and I'd like to avoid doing this if at all possible (if it even works).
As per a lengthy IRC discussion # http://webchat.freenode.net/?channels=sailsjs, it was suggested to create a policy and map that policy to all my controllers. In that policy, query the database for the 5 most recent posts, and set them to the req.recentposts. The problem with this solution is that, while the recent posts data will be passed to every controller, I still have to pass that req.recentposts data to my view -- making it so I still have to modify every single res.view({}) in every action. I don't have to have the database query in every action, which is good, but I still have to add a line of code to every action that renders a view... this isn't D.R.Y. and I'm looking for a better solution.
So, what is the proper solution, without needing to load that dynamic content in every controller action (a solution that adheres to D.R.Y. is what I'm lookng for), to get some dynamic content available to my layout.ejs file?
In folder /config you should create a file express.js and add something like that:
module.exports.express = {
customMiddleware: function(app){
app.use(function(req, res, next){
// or whatever query you need
Posts.find().limit(5).exec(function(err, posts){
res.locals.recentPosts = posts;
// remember about next()
next();
});
});
}
}
Then just make some simple loop in your view:
<% for(var i=0; i<recentPosts.length; i++) { %>
<% recentPosts[i].title %>
<% } %>
Here are some links to proper places in documentation:
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#express
and
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals
I found out another way to do this. What I did was to create a service that could render .ejs files to plain html by simply taking advantage of the ejs library already in sails. This service could either be invoked by the controller, or even passed as a function in the locals, and executed from within the .ejs. The service called TopNavBarService would look like:
var ejs = require('ejs');
exports.render = function() {
/* database finds goes here */
var userInfo = {
'username' : 'Kallehopp',
'real_name' : 'Kalle Hoppson'
};
var html = null;
ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
return html;
}
In the constroller it could look like:
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
This way you can create your customized ejs-helper that could even take arguments (although not shown here). When invoked, the helper could access the database and render a part of the html.
<div>
<%- renderNavbar() %>
</div>
I'm using jquery-ui tab example to add extra tabs. I changed that code to be able to add tabs that load a form via Ajax. I was able to create that just changing these:
var $tabs = $( "#tabs").tabs({
cache: true,
tabTemplate: "<li><a href='formularioAgricola.php' id='#{label}'>#{label}</a> <span class='ui-icon ui-icon-close'>Remove Tab</span></li>"
//ajaxOptions: a
});
So I changed the tabTemplate to load the same Form always.
My problem is that I'm not sure how to retrieve, either to tell that every tag from that form use jquery-ui stuff, like buttons, datepickers, etc.
In a regular form I would do something like:
$("#btnRevisar").button()
But when we talk about form load via Ajax it is different.
and also, how can I try to differ one form from other one, if they are all named with the same name, is it possible?
Thanks guys
Carlos.
Within the tabs docs page, tab titled "Events" there is a "load" event. The "ui" argument gives you access to an object that includes the current panel that is loaded. If you are using same ID on forms, beware that ID's must be unique in a page.
var $tabs = $( "#tabs").tabs({
cache: true,
tabTemplate: "<li><a href='formularioAgricola.php' id='#{label}'>#{label}</a> <span class='ui-icon ui-icon-close'>Remove Tab</span></li>",
/* add new option for load event*/
load: function( event, ui){
var $currTabContentPanel=$(ui.panel);
/* only look in currently loaded content for formClass*/
$currTabContentPanel.find('.formClass').doSomething()
}
});
I want to apply a class-name like "current" to an actionlink (in the master view) when it points to the current URL, in order to indicate an "on-state" in the UI. How might I do this?
UPDATE: I understand how to apply an attribute, I just need to know how to get the actionlink to know that it is pointing to the current page.
I suspect MVC's ViewContext.RouteData.Values["action"] would be useful for this. The RouteData has a range of key/value pairs (such as the Action mentioned here) that allow you to retrieve information about the current page and "view state" (for want of a better description) you're currently working with.
if it is only for visible use, I would use javascript with jQuery to quickly add a class for the 'current' link
$(document).ready(function() {
$('a.mylinks').each(function(i) {
if ($(this).attr('href') == document.URL) {
$(this).addClass('current');
}
});
});
<ul>
<li>link to current page</li>
<li>link to other page</li>
<li>link to another page</li>
</ul>