MVC SPA + Нокаут

Недавно мне было поручено создать SPA. Итак, я создал новый проект и выбрал SPA и обнаружил, что он загрузил все файлы, которые мне нужны, включая этот knockout.js.

Я новичок в knockout.js, поэтому я просмотрел несколько видеороликов, и я понял эту идею, но проект SPA просто не вычисляется для меня, поскольку это не приложение для одной страницы, потому что вам нужно перейти к новому URL-адресу для входа, регистрации, авторизации, управления учетной записью и т.д. (вы получаете идею).

Итак, глядя на код для индексной страницы, я вижу модель представления для homeView. Это выглядит так:

function HomeViewModel(app, dataModel) {
 var self = this;

 self.myHometown = ko.observable("");

 Sammy(function () {
 this.get('#home', function () {
 // Make a call to the protected Web API by passing in a Bearer Authorization Header
 $.ajax({
 method: 'get',
 url: app.dataModel.userInfoUrl,
 contentType: "application/json; charset=utf-8",
 headers: {
 'Authorization': 'Bearer ' + app.dataModel.getAccessToken()
 },
 success: function (data) {
 self.myHometown('Your Hometown is : ' + data.hometown);
 }
 });
 });
 this.get('/', function () { this.app.runRoute('get', '#home') });
 });

 return self;
}

app.addViewModel({
 name: "Home",
 bindingMemberName: "home",
 factory: HomeViewModel
});

и HTML выглядит так:

теперь, с точки зрения этого (исправьте меня, если я ошибаюсь), с дескриптором указано, что если есть переменная, называемая home, то отобразите ее (я предполагаю, что это то, что является именем bindingMembername).

Итак, видя, что могу догадаться, что если бы я добавил еще одну частичную страницу и включил ее. Я мог бы создать такую модель вида:

function DrawViewModel(app, dataModel) {
 var self = this;

 Sammy(function () {
 this.get('#draw', function () {
 app.home = null;
 });
 });

 return self;
}

app.addViewModel({
 name: "Draw",
 bindingMemberName: "draw",
 factory: DrawViewModel
});

поэтому, в теории, потому что это устанавливает, что app.home имеет значение null, когда кто-либо перебирается на #draw, тогда частичная часть дома не будет отображаться, аналогично, я мог бы добавить app.draw = null в маршрут sammy для homeViewModel, чтобы скрыть частичный результат,

Моя проблема с этим заключается в том, что он будет значительно сложнее, чем больше viewModels, которые я создаю. Итак, есть что-то, чего я не хватает? Есть ли более простой способ сделать это?

Моя конечная цель - переместить все страницы в SPA (включая страницы входа/регистрации).

Приветствия заранее, /r3plica

1 ответ

Ну, после немного беспорядка я узнал, как это сделать. В основном я переписал метод AddView и сделал его следующим:

// Other operations
self.addViewModel = function (options) {
 var viewItem = new options.factory(self, dataModel),
 navigator;

 // Add view to AppViewModel.Views enum (for example, app.Views.Home).
 self.Views[options.name] = viewItem;

 // Add binding member to AppViewModel (for example, app.home);
 self[options.bindingMemberName] = ko.computed(function () {
 if (self.view() !== viewItem) {
 return null;
 }

 return new options.factory(self, dataModel);
 });

 if (typeof (options.navigatorFactory) !== "undefined") {
 navigator = options.navigatorFactory(self, dataModel);
 } else {
 navigator = function () {
 self.view(viewItem);
 };
 }

 // Add navigation member to AppViewModel (for example, app.NavigateToHome());
 self["navigateTo" + options.name] = navigator;
};

вы можете видеть, если вы хотите проверить, отличается ли текущий удерживаемый вид тем, который я добавляю. Если это так, то я возвращаю значение null (это то, как я могу скрыть любые виды, которые я не использую). Чтобы ответить на мой вопрос дальше, мне нужно было разработать способ перехода на страницу входа в систему, если пользователь не был зарегистрирован.

Опять же в app.viewmodel.js я добавил несколько наблюдаемых свойств:

// UI state
self.user = ko.observable(null);

self.loggedIn = ko.computed(function () {
 return self.user() !== null;
});

и в моем новом login.viewmodel.js я добавил эту функцию:

// Operations
self.login = function () {
 self.loggingIn(true);

 dataModel.login({
 grant_type: "password",
 username: self.userName(),
 password: self.password()
 }).done(function (data) {
 if (data.userName && data.access_token) {
 app.navigateToLoggedIn(data.userName, data.access_token, self.rememberMe());
 } else {
 //self.errors.push("An unknown error occurred.");
 }
 }).fail(function (jqXHR, textStatus, error) {
 dataModel.displayError(jqXHR);
 }).always(function () {
 self.loggingIn(false);
 });
};

важный бит здесь - метод app.naviateToLoggedIn. Это находится в app.viewmodel.js и выглядит следующим образом:

// UI operations
self.navigateToLoggedIn = function (userName, accessToken, persistent) {
 if (accessToken) {
 dataModel.setAccessToken(accessToken, persistent)
 }

 self.user(new UserViewModel(self, userName, dataModel));
 self.navigateToHome();
};

userViewModel мертв:

function UserViewModel(app, name, dataModel) {
 var self = this;

 // Data
 self.name = ko.observable(name);

 // Operations
 self.logOff = function () {
 dataModel.logout().done(function () {
 app.navigateToLoggedOff();
 }).fail(function (jqHXR) {
 dataModel.displayError(jqHXR);
 });
 };

 return self;
}

и, наконец, чтобы получить начальную нагрузку в файле home.viewmodel.js js, у меня есть это выражение sammy:

Sammy(function () {
 this.get('#home', function () {
 if (app.loggedIn()) {
 app.navigateToHome();
 } else {
 window.location.hash = "login";
 }
 });
 this.get('/', function () { this.app.runRoute('get', '#home') });
});

licensed under cc by-sa 3.0 with attribution.