Properly separating the data model and view model - javascript

I am asking this in the context of AngularJS, but this question could really be applied to any language. So in a web application we have a use case where we need to fetch some data from a server (HTTP request) and then display that data in the UI.
So lets say our application is displaying a list of Books. Our process would look like this:
Run a GET request to /api/books to get a list of all our books
(optional) Transform the server-data-model to a client-data-model if needed
Bind the models to the $scope so they are accessible via the view
Iterate through the models on the $scope and display them in the HTML
At this point lets say we have a simple list of checkboxes with a book title next to it like this:
<ul>
<li ng-repeat="book in vm.Books">
<input type="checkbox" ng-model="<HERE>" name="my-books" />
<label>{{book.title}}</label>
</li>
</ul>
As you can see, in this template we reference the book.title in order to display it in the page. However, you can also see that the ngModel is unknown. This is where I am not sure what to do. The simple solution is to just tack on a UI model for use in the UI. This means that in step 2 above we would do book.UI = {} to every single model, then when we need to send that model back to the server we would have to do delete book.UI to clean it back up.
Doing this would allow our template to look like this now:
<ul>
<li ng-repeat="book in vm.Books">
<input type="checkbox" ng-model="book.UI.isSelected" name="my-books" />
<label>{{book.title}}</label>
</li>
</ul>
Now we can control when a book is selected via the checkbox input. This work OK, but it doesn't separate our concerns enough and there are side effects to using this pattern.
I'm sure there is a abstract design pattern that could solve this that isn't implementation specific, I just am not aware of any myself. Does anyone have any advice on how to obtain this kind of flexibility in the front end but separates our view models and data models completely so we don't have to do any "clean up" work?

You can use book.title as a dynamic object key. By default, the key value will be undefined, and it is set to true when the box is checked. If unchecked, the value will be set to false.
var checkedBookTitles = {};
<input type="checkbox" ng-model="checkedBookTitles[book.title]" />
If book.title = 'Javascript', then checkedBookTitles['Javascript'] = true when the proper checkbox is checked, it becomes false when unchecked.

Related

How to check which items in an asp:Treeview are checked client side

I have an asp page that has a treeview control on it, with checkboxes. I want to be able to check client side (javascript) which items have been checked.
Now when I view the source of the page, the tree is made up of table elements and I see this on a checked item:
<input type="checkbox" name="TreeView1n0CheckBox" id="TreeView1n0CheckBox" checked="checked" />
So I could loop around all the <input> elements, but I was wondering if there was a better way of doing this (and yes it would be easier on the Server, but I want to do this on the client).
The other thing I need to figure out is how I get back to the ID of the item in the Treeview.
Any suggestions?
Select the checked ones, convert to an array, then use map to get their IDs.
var CheckedElements = Array.from(document.querySelectorAll('input[type="checkbox"]:checked')).map(function(x){ return x.getAttribute('id') });

Can I make ng-model data available across multiple divs that are hidden and shown at runtime?

I have a problem with some data I want to use as part of a signup form in angular.js. I have the form split out into multiple "steps" - such as company account information, then admin user information, and finally, payment information. This is common in many web applications, so I know it has to be possible.
I have three divs which house each section of the form, as follows :
<div class="lc-block" id="l-register1" data-ng-class="{ 'toggled': lctrl.register1 === 1 }" data-ng-if="lctrl.register1 === 1">
<div class="lc-block" id="l-register2" data-ng-class="{ 'toggled': lctrl.register2 === 1 }" data-ng-if="lctrl.register2 === 1">
<div class="lc-block" id="l-register3" data-ng-class="{ 'toggled': lctrl.register3 === 1 }" data-ng-if="lctrl.register3 === 1">
As you can tell here, these three sections are hidden and shown, based on some ui interaction which changes the valus of variables to make a given "step" appear.
So here is my main issue : I want data from a model in "l-register1" to still be available when I am on the third step, for example, if I have the following input field inside "l-register1"...
<input type="text" class="form-control" ng-model="client" placeholder="Company name">
... and I hit "next" - I would like to still be able to retrieve that data during steps 2, and 3 - as I will obviously need it after all the data is in place, to send it off to my API (which I already have working)
Any help with this would be awesome, I have been banging my head against a wall all day, trying to get this working!
Just put all your ng-model and associated variables in one controller and you can hide and show your different div's based on conditional variables. Thus, as you put all your variable references within one controller it will automatically preservers the data associated with it. Also if you would like to use different controllers for the different page than you can also achieve the same. In that case you need to make service and share the data between two controllers. Just build the service which maintain your shared object and the controllers will handle with the reference. I have explained more with detail information here. In totality that's what whole angular is all about single page application.

Angular populate ng-repeat and ng-model

In my app I have a widget that is used on multiple pages and the selections made on the widgets are to be transferred between pages. So if I select something in the widget on the homepage and click 'continue' which then takes me to a new page, the widget should be pre-populated with the selections made on the homepage.
My widget follows the following format (although not exact for simplistic explanations):
<li ng-repeat="device in devices track by $index">
<select name="model[{{$index}}]" ng-model="selectedManufacturer" ng-options"...">
<select name="model[{{$index}}]" ng-model="selectedModel" ng-options"...">
</li>
It's the values of the ng-models inside the repeat statement that contain the key data in the widget that needs to be transferrable.
The number of devices needs to be transferrable too but that will be easy as devices is just an array of numbers so selectedModel.length -1 will equal the value of devices on the secondary pages.
Is it possible to pre-populate the values of ng-models?
Yes, you can prepopulate values of ng-models (or any scope variable) using ng-init
If you want to pre-populate the value in your ng-model which would mean a default/inital value in your drop-down. This can be achieved by doing the following:-
$scope.selectedManufacturer = listOfManufacturer[0];
$scope.selectedModel = listOfSelectedModel[0];

backbone JS Model / Collection (Retrieving Checked Box Ticked Value)

I currently have a list of item that is being loaded based on URL from collection.
Now i need to filter this list of item , currently the items are being populated manually hardcoded in template(html)
<li>
<label><input type="checkbox" id="internship" value="I"></label></li>
Should i populate this using model & collection instead, the question to which method which i'm asking for advice is based on How can i collect the VALUE of the checkbox TICKED.
If box is ticked , my URL sent will be different , to retrieve a new set of URL with queries.
Any advice would be greatly appreciated
I would suggest use model & collection to render this list, this way you don't have to query DOM every time you want to check state of view. Also you change URL by subscribing change event on model and collection as needed.

NodeJS + JS: generating dynamic links, depending on current user selection

I'm trying to create a simple sorting option for posts in my blog. The problem is the last thing I want to use is a JS-based redirections because of the fact some users don't have JS enabled in their browsers, thats why they wont be able to sort posts in me blog. Let me give you an example:
I have several categories in my blog:
//categories selection
<ul>
<li class="active"><a id="cat1" href="/?category=music">Music</a></li>
<li><a id="cat2" href="/?category=photo">Photo</a></li>
<li><a id="cat3" href="/?category=cinema">Cinema</a></li>
<li><a id="cat4" href="/?category=computers">Computes</a></li>
</ul>
Also, I have two sorting options:
//sorting options
<div>
<a class="active">Last posts</a>
<a>Last comments</a>
</div>
Depening on current active elements, user is redirected on page with such parameters, e.g. '/?category=music&sort=posted' or '/?category=personal&sort=commented'.
For example, lets take that in categories selection 'CINEMA' tab is active at this moment (
<li class="actvie"><a id="cat3" href="/?category=cinema">Cinema</a></li>
). So, if user clicks Last comments link, it should redirect to
'/?category=cinema&sort=comments'
Another example: currently Last comments is active (
<a class="active">Last comments</a>
). User clicks on Computes in category selection and it should redirect to
'/?category=computers&sort=comments'.
So, are there any variants for performing such feature without JS? If no, could you suggest me the most elegant solution except manually running over every element in category and sorting optiona and generation link with JS/jQuery?
Thanks in advance!
SERVER SIDE:
db.collection("posts", function (err, collection) {
//getting posts dependinc on requested category
collection.find({category: req.query['category']}, {sort: [['time_added', -1]], limit:20}, function (err, posts) {
//getting posts and rendering page
});
});
UPDATE: I've found a so-so solution. For a separate category I render two div's with different posts list. One for 'Last posted', the second - for 'Last commented'. And the sort selector will just hide one div and shows another. The problem is just twice data size transfering to client side. I know, it will require a bit JS, but the main category links would be clear without '#'-hrefs. And sort options - it's just a toogle, it may not have real link.
Seems like you are doing a page refresh for selecting a new category. Use the selected category parameter to determine the URL of the sorting options. Would need some more code from your server side to give you a more concrete example.
If you don't want to use Javascript you will have to generate the href-attribute of your sorting links <a class="active">Last posts</a> dynamically based on which category is selected. How are you rendering the page today? Just static files? Have a look at a template engine like mustache.js and then you could do it like this:
<a class="active" href="/?category={{category}}&sort=comments">Last posts</a>
Have a look at this tutorial for an Node.js example using mustache.js
http://mrjaba.posterous.com/a-gentle-introduction-to-nodejs
Edited after your comment: Or something like this using EJS
<div>
Last posts
Last comments
</div>
Are you talking about doing the actual sorting on the client side or the server side? If the latter, there's no problem; just stick with the URLs you have and have the server rewrite them and redirect to the new ones (if you even have to do that; you could just treat the "shorter" URLs as the actual ones for the sorted content). This is no way relies on client-side scripting being available.
You can, of course, implement client-side sorting on top of this as a convenience for users who do have client-side scripting available; the key here is to use unobtrusive JavaScript (e.g. install handlers at load time to intercept clicks on the sorting links).

Categories