In Jade how is this interpreted ? <%= lastName %> - javascript

I currently have my code like this but the first name appears the way it is being shown. I am trying to figure out what this is in jade, because this is not right.
Jade File
div.centerContent
script(type="text/javascript", src="/js/main.js")
h4 User goes here with equal before it no space
div#user
p!= "<%=firstName%>"
| <%=lastName%>
p!="<%= email %>"
p <%=phone%>
p <%=birthday%>
button.edit Edit
script(id="userTemplate", type ="text/template")
p <%=firstName%> <%=lastName%>
p <%=email%>
p <%=phone%>
p <%=birthday1%>
button.edit Edit
script(id="userEditTemplate", type ="text/template")
div
form(action="#")
input(type="text", class="firstName", value="<%= firstName %>") input(type="text", class="lastName", value="<%= lastName %>")
input(type="email", class="email", value="<%= email %>")
input(type="date", class="birthday", value="<%= birthday %>")
button.save Save
button.cancel Cancel
hr
Here I will include my main.js file maybe I am doing something wrong there.
main.js
(function () {
window.App = {
Models: {},
Collections: {},
Views: {},
Templates: {},
Router: {}
};
// MODEL
App.Models.User = Backbone.Model.extend({
defaults: {
firstName: 'first',
lastName: 'last',
email: 'Email',
phone: '222',
birthday: 'date'
},
validate: function (attrs) {
if (!attrs.firstName) {
return 'You must enter a real first name.';
}
if (!attrs.lastName) {
return 'You must enter a real last name.';
}
if (attrs.email.length < 5) {
return 'You must enter a real email.';
}
if (attrs.phone.length < 10 && attrs.phone === int) {
return 'You must enter a real phone number, if you did please remove the dash and spaces.';
}
if (attrs.city.length < 2) {
return 'You must enter a real city.';
}
},
initialize: function() {
user.on('invalid', function (model, invalid) {
console.log(invalid);
});
}
});
//VIEW
App.Views.User = Backbone.View.extend({
model: App.Models.User,
//tagName: 'div',
//id: 'user',
//className: 'userProfile',
template: _.template($("#userTemplate").html()),
editTemplate: _.template($("#userEditTemplate").html()),
initialize: function (){
}
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
events: {
'click button.edit': 'editProfile',
// 'click button.save': 'saveEdits',
'click button.cancel': 'cancelEdits'
},
editProfile: function () {
this.$el.html(this.editTemplate(this.model.toJSON()));
},
cancelEdits: function() {
this.render();
}
});
//start history service
Backbone.history.start();
var user = new App.Views.User({el: 'div #user'});
user.render();
})();

As far as Jade sees, "<%= firstName %>" is just a String literal. But, it will HTML encode it:
<input type="text" class="firstName" value="<%= firstName %>">
To keep the value as-is, add a ! before the = to skip encoding.
input(type="text", class="firstname", value!="<%= firstName %>")
<input type="text" class="firstName" value="<%= firstName %>">
From the documenation:
Code buffered by = is escaped by default for security, however to output unescaped return values you may use !=:
p!= aVarContainingMoreHTML
Also note that, if you're using an older version of Jade, the contents of script elements may be treated in whole as text literals.
Jade version 0.31.0 deprecated implicit text only support for scripts and styles. To fix this all you need to do is add a . character after the script or style tag.
Before 0.31.0, your view would render as (abridged):
<script id="userEditTemplate" type="text/template">
div.userProfile
form(action="#")
# ...
</script>

Related

Knockout custom validation: How to check if observable is equal to a specific value?

I'm new with Knockout.js, and I would like to check if a field of my form has a specific value. Actually, I only check if it is required or not. What should I do?
Here's what I have in my html page:
<div data-bind="visible: !Vm.isValid()" class="text-danger">Fill each field to send data, otherwise show this message</div>
<input data-bind="enable: Vm.isValid()" type="button" value="Send data!" />
That's what my vm.js file looks like:
window.Vm = ko.validatedObservable({
name : ko.observable().extend({ required: true })
});
I would make something like this, but I don't know how to do it:
var found = "found";
window.Vm = ko.validatedObservable({
name: ko.observable().extend({
required: true,
function: {
if (this.val() == found)
return true; // invalid value, can't submit my form
}
})
});
I would actually recommend against using the Knockout Validation library, as it hasn't been maintained for years. It's an outdated solution to a problem that doesn't really exist anymore. In 2019 you can just use the form validation that is native to every modern browser. Just put a required attribute on your form fields and the form will not submit if not all required fields have been filled out.
If you want it to be a little more dynamic, you could do something like this:
function ViewModel() {
var vm = this;
vm.name = ko.observable();
vm.required = ['name', 'email'];
vm.isRequired = isRequired;
function isRequired(field) {
return vm.required.indexOf(field) > -1;
}
}
And use the attr binding to set the required attribute based on the array of required elements in your viewmodel.
<input type="text" data-bind="textInput: name, attr: { required: isRequired('name') }">
You can use a custom validator like this (Documentation):
var found = "found";
var Vm = ko.validatedObservable({
name: ko.observable().extend({
required: {
message: "This is a required field",
},
validation: {
validator: (val, paramValue) => {
// "val" has the value entered in the field
// "paramValue" has the value set in "params"
return val === paramValue
},
message: "The value is not " + found,
params: found
}
})
});
ko.applyBindings(Vm)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<input type="text" data-bind="value: name" />
I have taken data as ["A","B"], and search based upon the same data.
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
target.data = ko.observableArray(["A","B"]);
target.found = ko.observable();
target.foundMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
target.found(target.data().find(function(element){ return newValue==element;}));
target.found()?target.foundMessage("element has found"):target.foundMessage("element has not found");
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
function AppViewModel(first) {
this.firstName = ko.observable(first).extend({ required: "" });
}
ko.applyBindings(new AppViewModel("C"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<p data-bind="css: { error: firstName.hasError }">
<input data-bind='value: firstName, valueUpdate: "afterkeydown"' />
<span data-bind='visible: firstName.hasError, text: firstName.validationMessage'> </span>
<span data-bind='visible: (!firstName.hasError()), text: firstName.foundMessage'> </span>
</p>

Login page in Oracle jet

Hi I am creating an application using Oracle JET in which after I click the Login button in the LoginTest page, it should take me to the Homepage after validation. I have managed to validate the input but I couldn't route it to the Homepage. I have tried using multiple binding but it is of no use. Could someone please help.
HTML CODE
h1>logintest</h1>
<div align="center">
<label for="username">Username</label>
<input id="username" type="text" required
data-bind="ojComponent: {component: 'ojInputText',
validators: [{type: 'regExp', options: {pattern: '[a-zA-Z0-9]{3,}',
messageDetail: 'You must enter at least 3 letters or numbers'}}],
invalidComponentTracker: tracker}" /><br /><br />
<label for="password">Password</label>
<input id="password" type="password" required
data-bind="ojComponent: {component: 'ojInputPassword',
validators: [{type: 'regExp', options : {pattern: '(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,}',
messageSummary : '{label} too Weak',
messageDetail: 'The password must contain atleast one uppercase, one lowercase, one number and must be 6 digits long'}}],
invalidComponentTracker: tracker}" /><br /><br />
<a class="oj-button-primary oj-button-xl"
href="http://localhost:8383/Test/index.html?root=home" id="create" type="button"
data-bind="ojComponent: {component: 'ojButton',
label: 'Login',
disabled: shouldDisableCreate()},
click: onClick"></a>
</div>
JAVASCRIPT CODE
define(['ojs/ojcore', 'knockout', 'ojs/ojinputtext', 'ojs/ojbutton', 'ojs/ojknockout-validation', 'ojs/ojmodel'
], function (oj, ko) {
/**
* The view model for the main content view template
*/
function logintestContentViewModel() {
var self = this;
self.tracker = ko.observable();
self.username = ko.observable("");
self.password = ko.observable("");
self.clickedButton = ko.observable();
self.buttonClick = function(data, event)
{
var trackerObj = ko.utils.unwrapObservable(self.tracker);
if (!this._showComponentValidationErrors(trackerObj))
{
return;
}
};
self.routePage = function(data,event)
{
self.clickedButton(event.currentTarget.id);
return true;
};
self.onClick = function()
{
self.buttonClick();
self.routePage();
}
self.shouldDisableCreate = function()
{
var trackerObj = ko.utils.unwrapObservable(self.tracker),
hasInvalidComponents = trackerObj ? trackerObj["invalidShown"] : false;
return hasInvalidComponents;
};
self._showComponentValidationErrors = function (trackerObj)
{
trackerObj.showMessages();
if (trackerObj.focusOnFirstInvalid())
return false;
};
}
return logintestContentViewModel;
});
If you are using ojRouter, then you can simply use
oj.Router.go("route name");
If you're not using ojRouter, then you can use the location object. Something like:
window.location.pathname='/homepage'
I recommend using ojRouter and it's canEnter() method for things like this.
Router cookbook demo:
http://www.oracle.com/webfolder/technetwork/jet/jetCookbook.html?component=router&demo=simple
JSDocs for Router canEnter method
http://www.oracle.com/webfolder/technetwork/jet/jsdocs/oj.RouterState.html
You can use
oj.Router.rootInstance.go('homepage');

Return a collection inside a select tag

I've got a collection of models with different properties and I need to render some of them inside the <select> tag, each model as an <option>. The view that renders this collection is nested in another view. Here is my collection:
var UserCollection = Backbone.Collection.extend({
url: 'http://localhost:3000',
developers: function () {
var developers = this.where({role: "developer"});
return new UserCollection(developers);
}
});
And this is my view for the select tag:
var InterviewersView = Backbone.View.extend({
initialize: function () {
this.template = _.template(interviewersTemplate);
this.collection = new UserCollection();
this.collection.fetch();
this.interviewers = this.collection.developers();
},
render: function () {
this.$el.html(this.template());
return this;
}
});
and this is my template:
<label>Interviewer</label>
<select class="form-control" id="js-interviewer-selector">
<% _.each(this.interviewers.toJSON(), function(interviewer) { %>
<option value="<%= interviewer.login %>">
<%= interviewer.firstName %> <%= interviewer.lastName %>
</option>
<% }) %>
</select>
The template renders inside another view properly and exactly as I need, but there's no options inside the select tag and it is empty. What am I doing wrong?
Repo with my project
Try to pass your collection to your view like this
render: function () {
var that = this;
that.$el.html(that.template({interviewers: that.interviewers}));
return this;
}
and in your template use underscore _.each function to dive collection to individual interviwer like this
<select class="form-control" id="js-interviewer-selector">
<% _.each(interviewers, function(interviewer) { %>
<option value="<%= interviewer.login %>">
<%= interviewer.firstName %> <%= interviewer.lastName %>
</option>
<% }) %>
</select>
It must work now:)
So, the problem was the same as in this question -- because of asynchronous nature of .fetch() method the collection was loaded after the view was rendered, so it received nothing. So, removing .fetch() method from initialize and adding it to render worked. Here's the complete code:
var InterviewersSelect = Backbone.View.extend({
initialize: function () {
this.template = _.template(interviewersTemplate);
this.collection = new UserCollection();
},
render: function () {
var self = this;
this.collection.fetch({
data: {
role: "developer"
},
success: function(collection) {
var interviewers = collection.map(function(item) {
return item.toJSON();
});
self.$el.html(self.template({interviewers: interviewers}));
}
});
return this;
}
});

Backbone model.get('key') undefined after .fetch() call, even inside success callback

I'm new to Backbone.js, and just finished running through a basic tutorial to create a "user list" system (https://www.youtube.com/watch?v=FZSjvWtUxYk) where all the templates, scripts, etc are created inline. I got everything working pretty easily, so I decided to try and modularize things since I know that's the best practice. I'm following this guide to the AMD methodology (https://cdnjs.com/libraries/backbone.js/tutorials/organizing-backbone-using-modules) and have everything working properly except for one thing - when editing a user, the "current" data isn't being loaded into the form. All of the issues I've found on SO and other places so far have been solved by putting the template generating code inside the success: callback of the .fetch() call, but I'm already doing that.
Here's the code:
(I'm leaving out the main.js and app.js that handle the require.js configuration, router init, etc. They seem to be working just fine.)
// Filename: router.js
define([
'jquery',
'underscore',
'backbone',
'views/userList',
'views/editUser'
], function($, _, Backbone, UserListView, EditUserView){
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'new': 'editUser',
'edit/:id': 'editUser'
}
});
var initialize = function(){
var app_router = new AppRouter;
app_router.on('route:home', function(){
var userListView = new UserListView();
userListView.render();
});
app_router.on('route:editUser', function(id) {
var editUserView = new EditUserView();
editUserView.render({ id: id });
});
Backbone.history.start();
};
return {
initialize: initialize
};
});
views/editUser.js
// Filename: views/editUser
define([
'jquery',
'underscore',
'backbone',
'models/user',
'text!/templates/editUser.html'
], function($, _, Backbone, UserModel, rawEditUserTemplate) {
var userListView = Backbone.View.extend({
// Element to use for this view
el: $('.page'),
// Function to call when this view is rendered
render: function(options) {
var that = this;
// If there is an ID, we are editing
if ( options.id ) {
// Create the user, passing the ID
that.editUser = new UserModel({ id: options.id });
// Fetch the user data
that.editUser.fetch({
// When the fetch is returned
success: function(userData) {
// Generate the template and pass the data in
var editUserTemplate = _.template( rawEditUserTemplate );
that.$el.html(editUserTemplate({ user: userData }));
}
})
}
else { // We are creating a new user
// Generate the template with an empty user
var editUserTemplate = _.template( rawEditUserTemplate );
this.$el.html(editUserTemplate({ user: null }));
}
},
events: {
'submit .edit-user-form': 'saveUser',
'click .delete': 'deleteUser'
},
saveUser: function(e) {
e.preventDefault();
// Get the details
var userDetails = $(e.currentTarget).serializeObject();
// Create a user model
var user = new UserModel();
// Save the user details
user.save(userDetails, {
success: function(user) {
Backbone.history.navigate('', { trigger: true });
}
});
},
deleteUser: function(e) {
e.preventDefault();
// Destroy the user we are editing
this.editUser.destroy({
// When the destroy is finished
success: function() {
// Back to home
Backbone.history.navigate('', { trigger: true });
}
});
}
});
// Our module now returns our view
return userListView;
});
templates/editUser.html
<form class="edit-user-form">
<legend><%= user ? 'Update' : 'Create' %> User</legend>
<div class="form-group">
<label for="firstname">First Name</label>
<input type="text" class="form-control" name="firstname" id="firstname" value="<%= user ? user.get('firstname') : '' %>" />
</div>
<div class="form-group">
<label for="lastname">Last Name</label>
<input type="text" class="form-control" name="lastname" id="lastname" value="<%= user ? user.get('lastname') : '' %>" />
</div>
<div class="form-group">
<label for="age">Age</label>
<input type="text" class="form-control" name="age" id="age" value="<%= user ? user.get('age') : '' %>" />
</div>
<hr />
<button class="btn btn-success" type="submit"><%= user ? 'Update' : 'Create' %></button>
<% if ( user ) { %>
<input type="hidden" name="id" id="id" value="<%= user.id %>" />
<button class="btn btn-danger delete">Delete</button>
<% }; %>
</form>
Using this code, I get a blank edit form regardless of whether or not I'm editing or creating, HOWEVER the "Create" vs "Update" text switch in the template is working properly. This means that a user object is in fact being passed, and when I add a console.log(user) into the template file, it is in fact showing me user data. When I log user.get('firstname') or any other attribute, however, it logs "undefined".
The issue was in my User model, which I didn't include above because I didn't understand at the time why it could be relevant.
I was defining it as:
var userModel = Backbone.Model.extend({
url: '/users'
});
When it should have been:
var userModel = Backbone.Model.extend({
urlRoot: '/users'
});
The wrong option was causing the API to return a collection rather than a model, so the .get() wasn't able to work properly.

Keep Knockout from running isValid() on page load

I want to add a data attribute (data-invalid) to a text field if it is invalid and remove it if it is valid. Here's the html and js:
<form data-bind="submit: submitFields">
First Name: <input type="text" runat="server" ID="FirstName" data-bind="value: firstName, valueUpdate: 'blur', attr: { 'data-invalid': !firstName.isValid()}"/>
<br/>
<button type="submit" >Submit</button>
</form>
var viewModel;
viewModel = function() {
self = this;
self.firstName = ko.observable().extend({
required: true,
notify: 'always'
});
//sets errors to an array of the error messages?
self.errors = ko.validation.group(this, { deep: true, observable: false })
self.submitFields = function(formElement) {
if (self.errors().length > 0) {
self.errors.showAllMessages();
return;
}
//submit
}
};
ko.applyBindings(new viewModel());
And a fiddle to test it out:
http://jsfiddle.net/frontenderman/HhtEZ/2/
My problem is that firstName.IsValid() runs on pageload. Is there an elegant way to get around this? All I can think of is doing something like subscribing to firstName and using a flag to set the data-attribute to null on the first run through my view model and then returning !firstName.isValid() on any of the subsequent runs.

Categories

Resources